irdavidnet
Banned
دوستان یه آپلودر آژاکس می خوام با php که به صورت درصدی نشون بده چقدر آپلود شده + progress هم داشته باشه ، دقیقاً مثل : parsaspce.com . ممنون
مرسی، دنبالش میگشتماینم redupload ولی از جاوا اپلت استفاده می کنه !!!!!!!!!!! که سرعتو پایین میاره
php ه دیگهمنم فکر کنم نمیاره ، حالا اسکریپته دیگری ندارید ؟ جز redupload ؟ که php باشه با همون مشخصاتی که گفتم ؟
#!/usr/bin/perl
#
# filechucker.cgi
#
# This program is the copyrighted work of Encodable Industries.
# Redistribution is prohibited, and copies are permitted only for
# backup purposes. You are free to modify the program for your
# own use, but you may not distribute any modified copies of it.
#
# Use of this program requires a one-time license fee. You can
# obtain a license here:
#
# http://encodable.com/filechucker/#download
#
# This software comes with no warranty. The author and many other
# people have found it to be useful, and it is our hope that you
# find it useful as well, but it comes with no guarantees. Under
# no circumstances shall Encodable Industries be held liable in
# any situation arising from your use of this program. We are
# generally happy to provide support to all our users, but we can
# make no guarantee of support.
#
# For more information about this program, as well as for help
# and support, please visit the following pages:
#
# Homepage: http://encodable.com/filechucker/
# Contact: http://encodable.com/contact/
my $version = "3.35";
$ENV{PATH} = '/bin:/usr/bin';
delete @ENV{'IFS', 'CDPATH', 'ENV', 'BASH_ENV'};
($ENV{DOCUMENT_ROOT}) = ($ENV{DOCUMENT_ROOT} =~ /(.*)/); # untaint.
my %PREF = ();
############################################################################
###
### User preferences ("PREFs") section: adjust these variables
### to suit your own server/setup/tastes. If you'd rather store
### and edit these in a separate file (to make upgrades easier,
### etc.) then create a file called filechucker_prefs.txt in the
### same directory as the filechucker.cgi script. The format for
### the lines is the same as here in the script itself; you could
### just copy or move this entire section into your separate PREFs
### file if you'd like. Comments (that is, lines starting with a
### pound-sign) and blank lines are allowed in the separate PREFs
### file, too.
###
############################################################################
#
#
# PREFs Table of Contents:
#
#
# PREFs Section 01: Debugging.
# PREFs Section 02: Paths and Directories.
#
# *Note: stop here and get the script running before customizing anything else.
#
# PREFs Section 03: Security.
# PREFs Section 04: User-directories.
# PREFs Section 05: Subdirectories.
#
# *Note: User-directories and subdirectories are two separate things.
#
# PREFs Section 06: Email Notification.
# PREFs Section 07: Upload Form Configuration.
# PREFs Section 08: Upload Restrictions.
# PREFs Section 09: Processing Uploads.
# PREFs Section 10: Post-Upload.
# PREFs Section 11: File-List Configuration.
# PREFs Section 12: Database Setup.
# PREFs Section Z: Misc Settings Not Usually Needed.
#
############################################################################
# PREFs Section 01: Debugging.
############################################################################
# The enable_debug PREF prints some debugging output in an HTML comment at
# the bottom of the page, if you pass "debug" as the query-string. And the
# show_errors_in_browser PREF causes any fatal errors to be printed right in
# the browser, in addition to in your server's error log. Enable both of
# these until you get FileChucker working properly, then disable them.
#
$PREF{enable_debug} = 'no';
$PREF{show_errors_in_browser} = 'yes';
# PREFs Section 02: Paths and Directories.
############################################################################
# Some servers seem to not set $ENV{DOCUMENT_ROOT} properly (in one case,
# for users who serve pages from their home directories), so we'll make
# our own version. Most of the time it should be set to the docroot,
# but if necessary you can adjust this here. The default value is:
#
# $PREF{DOCROOT} = $ENV{DOCUMENT_ROOT};
#
# IIS users will often need to set it like this:
#
# $PREF{DOCROOT} = 'c:\inetpub\wwwroot';
#
$PREF{DOCROOT} = $ENV{DOCUMENT_ROOT};
# PREFs Section 02: Paths and Directories.
############################################################################
# This is where the uploaded files will go. It must be world-readable
# and world-writable, aka "chmod a+rwx" or "chmod 0777".
#
# On most servers this will be in the DOCROOT, in which case we'll prepend
# your DOCROOT to whatever you set uploaded_files_dir to. If for some
# reason you want to specify it with an absolute path, or a path that's
# relative to the current directory instead of the DOCROOT, then set the
# _is_in_docroot PREF to no.
#
# And by default you should put the images (file/folder icons, logos, some
# rounded corners, etc, from filechucker-images.zip on the FileChucker web
# page) in the /upload/ directory, but you can adjust that too.
#
$PREF{uploaded_files_dir} = '/upload/files';
$PREF{uploaded_files_dir_is_in_docroot} = 'yes';
$PREF{path_to_filelist_images} = '/upload/';
# PREFs Section 02: Paths and Directories.
############################################################################
# If you set uploaded_files_dir to a path outside your webspace, then we
# won't be able to directly link to the files from your website, because
# they aren't in the DOCROOT. If you're doing something like manually
# moving the files to somewhere else within your DOCROOT afterwards, then
# enter that path here. Otherwise just leave this commented out. Note:
# don't include an ending slash on this.
#
#$PREF{uploaded_files_urlpath} = '';
# PREFs Section 02: Paths and Directories.
############################################################################
# This is where datafiles (which are temporary: only needed while a given
# upload is in progress) are stored. This must be world-readable and
# world-writable. By default, we set its _in_docroot PREF to 'no' because
# by default the data directory gets placed at the same location as the
# filechucker.cgi script itself, so we don't need to prepend the value of
# DOCROOT onto it; we can access it directly since it's in the same dir
# we're running in. The default settings are:
#
# $PREF{datadir} = 'fcdata';
# $PREF{datadir_is_in_docroot} = 'no';
#
# Alternatively you can set it with an absolute path, like this:
#
# $PREF{datadir} = '/var/www/mysite.com/cgi-bin/fcdata';
# $PREF{datadir_is_in_docroot} = 'no';
#
# Or this:
#
# $PREF{datadir} = 'c:\inetpub\wwwroot\cgi-bin\fcdata';
# $PREF{datadir_is_in_docroot} = 'no';
#
$PREF{datadir} = 'fcdata';
$PREF{datadir_is_in_docroot} = 'no';
# PREFs Section 02: Paths and Directories.
############################################################################
# The logfiles are just used during each upload, to keep track of how much
# data has been sent, how much time has elapsed, etc. They aren't used at
# all after an upload has completed, so you probably want them deleted right
# away. Note that these are different from the info-files which contain a
# permanent record of the upload including info like who uploaded what, the
# uploader's IP, date/time, etc.
#
$PREF{delete_logfiles_immediately} = 'yes';
# PREFs Section 02: Paths and Directories.
############################################################################
# If you want to access FileChucker at a short URL like yoursite.com/upload/
# instead of yoursite.com/cgi-bin/filechucker.cgi, then you can do the
# following:
#
# If you're using SSI (Apache and IIS both support this), then put the
# following line into /upload/index.shtml on your server:
#
# <!--#include virtual="/cgi-bin/filechucker.cgi?$QUERY_STRING" -->
#
# Or if your server runs PHP, you can put the following line into
# /upload/index.php on your server:
#
# <?PHP virtual("/cgi-bin/filechucker.cgi"); ?>
#
# Then set the 'here_' PREFs like this:
#
# $PREF{here_uploader} = '/upload/';
# $PREF{here_filelist} = '/upload/';
# ...
#
# Otherwise leave these set to $ENV{SCRIPT_NAME}.
#
# Note that in most cases these should all be set to the same value, i.e.
# unless you've actually set up multiple short URLs to point to the CGI
# script. And if you only set the single $PREF{here} value, then the
# others will automatically be set to that value.
#
$PREF{here} = $ENV{SCRIPT_NAME};
#$PREF{here_uploader} = $ENV{SCRIPT_NAME};
#$PREF{here_uploadcomplete} = $ENV{SCRIPT_NAME};
#$PREF{here_filelist} = $ENV{SCRIPT_NAME};
#$PREF{here_login} = $ENV{SCRIPT_NAME};
#$PREF{here_errorpage} = $ENV{SCRIPT_NAME};
# PREFs Section 03: Security.
############################################################################
# Password Protection, Option 1 of 4 (simple; no usernames):
#
# If you want to require just a password (without a username) for
# access to the uploader and/or the list of uploaded files, then you
# can set these hashes. Go to:
#
# yoursite.com/cgi-bin/filechucker.cgi?makePasswordHash
#
# ...enter the password you want to use into that page, and it
# will generate a "hash" of the password, which is a string that
# looks something like this:
#
# cdfc81932491375c34c842bcebc7dc15
#
# Copy and paste the hash into one of the following preferences.
# Then when you want to log in, enter the password, not the hash.
# (This is so that we don't store the actual password on disk, which
# would be very insecure.)
#
# We specify two possible user-levels: member and admin. If you
# want, you can use just one of them, and have a single password
# for both uploading and viewing the file-list. Or you can specify
# both, and set the "must_be_" preferences accordingly, so that only
# the admin can view the uploaded files. Or vice-versa. Or you
# could require no password to view the file-list, but require one
# to upload. Etc, etc. Just set the prefs accordingly.
#
# Note that the admin is automatically a "member" too, so someone
# with the admin password automatically has access to anything that
# requires the member password.
#
$PREF{member_password_hash} = '';
$PREF{admin_password_hash} = '1ba86cf7548z8291f332db683362c544';
# PREFs Section 03: Security.
############################################################################
# Password Protection, Option 2 of 4 (full-featured; unlimited usernames):
#
# If you need a full-featured login system (with unlimited usernames, each
# having its own password), instead of FileChucker's simple built-in
# password system which has just 2 passwords and no usernames, then you
# may want to use our UserBase application:
#
# http://encodable.com/userbase/
#
# FileChucker integrates fully with UserBase, and if you set the PREF
# "enable_userdirs" below, then each of your users will
# automatically have their uploads stored in their own directory.
#
# To integrate with UserBase, FileChucker needs to know the location of
# the UserBase data directory. On most servers this will be in the
# DOCROOT, in which case we'll prepend your DOCROOT to whatever you set
# userbase_data_dir to. If for some reason you want to specify it with
# an absolute path, or a path that's relative to the current directory
# instead of the DOCROOT, then set ...is_in_docroot to no.
#
# Finally, specify the URLs to UserBase on your server. Note that these
# are not full filesystem paths; they are within your server's DOCROOT.
# The default values are:
#
# logout_url = /cgi-bin/userbase/userbase.cgi?logout
# login_url = /login/
#
# If you don't have the nice short /login/ URL set up on your server
# (see UserBase homepage for instructions), then just set the login_url
# value to the full path to the userbase.cgi file.
#
$PREF{integrate_with_UserBase} = 'no';
$PREF{userbase_data_dir} = '/cgi-bin/userbase/data';
$PREF{userbase_data_dir_is_in_docroot} = 'yes';
$PREF{logout_url} = '/cgi-bin/userbase/userbase.cgi?logout';
$PREF{login_url} = '/cgi-bin/userbase/userbase.cgi';
#$PREF{login_url} = '/login/';
# PREFs Section 03: Security.
############################################################################
# Password Protection, Option 3 of 4 (use your site's existing login system):
#
# If your site already has a cookie-based login system, then you can set
# these PREFs to make FileChucker integrate with it. FileChucker will use
# the existence of the cookies specified here as confirmation that a user is
# logged in to your site. Note that this option is mutually exclusive with
# the integrate_with_UserBase option.
#
$PREF{integrate_with_existing_login_system} = 'no';
$PREF{member_username_cookie_name} = 'member_username';
$PREF{admin_username_cookie_name} = 'admin_username';
#$PREF{logout_url} = '/logout/';
#$PREF{login_url} = '/login/';
# PREFs Section 03: Security.
############################################################################
# (Pseudo-)Password Protection, Option 4 of 4 (automatic private directories):
#
# You can enable this serial_is_userdir option to get much of the benefit
# of usernames & passwords without actually having to use usernames or
# passwords. When configured this way, FileChucker will automatically put
# each new upload into a new unique private subdirectory, something like:
#
# yoursite.com/upload/?userdir=11832920981234098203458234098123
#
# This is primarily meant to facilitate single-use uploads, for instance
# where a person just wants to share one file one time; however by using
# the link provided at the end of the upload and in the notification email,
# the user can actually reuse the same uploads folder for as long as he wishes.
#
# In order to configure FileChucker this way, in addition to setting this
# serial_is_userdir PREF, you should also find & set the following:
#
# $PREF{keep_userdir_on_url} = 'yes';
# $PREF{enable_userdir_on_url} = 'yes';
# $PREF{enable_userdirs} = 'yes';
# $PREF{auto_create_userdirs} = 'yes';
# $PREF{must_be_member_to_upload} = 'no';
# $PREF{must_be_member_to_list_files} = 'no';
# $PREF{must_be_member_to_download} = 'no';
# $PREF{must_be_member_to_delete_items} = 'no';
# $PREF{hide_path_to_uploads_dir} = 'yes';
# $PREF{enable_subdirs} = 'no';
#
# $PREF{send_email_notifications} = 'yes';
# $PREF{email_notification_recipient_1} = '[email protected]';
# $PREF{sender_email_address} = '[email protected]';
# $PREF{smtp_server} = 'localhost';
# $PREF{email_subject} = 'New upload on yoursite.com';
#
# $PREF{top_textbox_1_singleline} = 'Sender Email Address:';
# $PREF{top_textbox_1_singleline_save} = 'yes';
# $PREF{top_textbox_1_singleline_email} = 'yes';
#
# $PREF{top_textbox_2_singleline} = 'Recipient Email Address:';
# $PREF{top_textbox_2_singleline_save} = 'yes';
# $PREF{top_textbox_2_singleline_email} = 'yes';
#
# If you'd rather not go through all the PREFs trying to find those, you
# may want to just set them in a separate PREFs file as explained here:
#
# http://encodable.com/filechucker/#upgrading
#
$PREF{serial_is_userdir} = 'no';
# PREFs Section 03: Security.
############################################################################
# Whether you're using UserBase or FileChucker's built-in password system,
# the following "must_be_*_to_*" PREFs control who can access what.
#
$PREF{must_be_member_to_upload} = 'no';
$PREF{must_be_admin_to_upload} = 'no';
$PREF{must_be_member_to_list_files} = 'no';
$PREF{must_be_admin_to_list_files} = 'no';
$PREF{must_be_member_to_download} = 'no';
$PREF{must_be_admin_to_download} = 'no';
$PREF{must_be_member_to_view_upload_info} = 'no';
$PREF{must_be_admin_to_view_upload_info} = 'no';
$PREF{must_be_member_to_move_items} = 'no';
$PREF{must_be_admin_to_move_items} = 'no';
$PREF{must_be_member_to_delete_items} = 'no';
$PREF{must_be_admin_to_delete_items} = 'no';
$PREF{must_be_member_to_order_items} = 'no';
$PREF{must_be_admin_to_order_items} = 'no';
$PREF{must_be_member_to_make_folder_thru_fileman} = 'no';
$PREF{must_be_admin_to_make_folder_thru_fileman} = 'no';
# PREFs Section 03: Security.
############################################################################
# Once you allow someone to download a file from your uploads area,
# they will know the path to all your uploads. If you don't want
# them to be able to see all the other files by just visiting that
# directory's address, you'll need to put a .htaccess file in that
# directory with the line "Options -Indexes" (without quotes).
# However, as long as they know the address, they can still try to
# guess filenames that might be in there. As an extra security
# precaution, you can set serialize_all_uploads, which adds a long
# pseudo-random number to each filename, making it virtually
# impossible that someone could guess the name of a file in the
# directory.
#
$PREF{serialize_all_uploads} = 'no';
# PREFs Section 03: Security.
############################################################################
# Choose whether the script should display a link to the list of
# uploaded files. Note that "members" includes "admins", and
# "strangers" includes everyone (i.e. members and admins too).
#
$PREF{show_link_to_uploads_for_strangers} = 'yes';
$PREF{show_link_to_uploads_for_members} = 'yes';
$PREF{show_link_to_uploads_for_admins} = 'yes';
# PREFs Section 03: Security.
############################################################################
# When an upload finishes, we display an "Upload Complete" page, which
# lists the names of the files that were uploaded, along with their
# sizes, and some other information. On this page, each filename is a
# link to download that file, unless you set these to 'no'.
#
$PREF{upload_complete_page_links_to_files_for_strangers}= 'yes';
$PREF{upload_complete_page_links_to_files_for_members} = 'yes';
$PREF{upload_complete_page_links_to_files_for_admins} = 'yes';
# PREFs Section 03: Security.
############################################################################
# Whether to display the login link in the footer-links at the bottom of
# the page. If you don't want to display it, then you log in by either
# trying to access a page you don't have access to (which will print the
# login link in the error message), or by passing ?login to the script.
# Of course if you're not configuring your FileChucker with any of the
# password PREFs then this is irrelevant.
#
$PREF{show_login_link} = 'yes';
# PREFs Section 03: Security.
############################################################################
# In various places -- the upload subdirectory drop-down box, the move-item
# page, etc -- we need to show the user a path to the uploaded files. The
# beginning of this path will be the value of your uploaded_files_dir if
# that's in your docroot, or else it'll be the value you set for
# uploaded_files_urlpath. But if you want that beginning part of the path
# to be hidden from your users, then enable this PREF. Note that the user
# can still see this part of the path whenever they actually download a
# file, since naturally we need to go through the whole path to get to the
# file.
#
$PREF{hide_path_to_uploads_dir} = 'no';
# PREFs Section 04: User-directories.
############################################################################
# Only allow each user to access their own upload directory. The user's
# directory is determined by the preferences you set below; it will either
# come from ?userdir=foo on the URL, or from a username cookie that's set
# by your site's existing login framework. If you don't want any kind of
# username-based directories, and you want all users to be able to upload
# to wherever they want, then don't set this. Finally note that even when
# this is set, administrators can still upload to and view any folder.
#
$PREF{enable_userdirs} = 'no';
# PREFs Section 04: User-directories.
############################################################################
# If you're dropping FileChucker into an existing system with lots of
# users, you may not want to manually create a user subdirectory for each
# one. In that case you can enable this, and then anyone who visits with
# ?userdir=foo or with foo in their username cookie will cause the username
# directory to be created automatically.
#
$PREF{auto_create_userdirs} = 'no';
# PREFs Section 04: User-directories.
############################################################################
# Enable ?userdir=username (or ?userdir=whatever) on the URL to automatically
# select the upload subdirectory. Note that this is probably insecure and
# you should use enable_userdir_from_cookie instead.
#
$PREF{enable_userdir_on_url} = 'no';
# PREFs Section 04: User-directories.
############################################################################
# If you're using enable_userdir_on_url, then you probably also want to set
# this keep_userdir_on_url option, so that when a user clicks on the various
# links like "Show Uploads," it keeps them inside their proper folder.
#
$PREF{keep_userdir_on_url} = 'no';
# PREFs Section 04: User-directories.
############################################################################
# If you want to use ?userdir=username (or ?userdir=whatever) on the URL, to
# automatically select the directory into which the user's files will be
# uploaded, then you may also want to set url_without_userdir_is_error, so
# that sneaky users can't try to manually manipulate the URL and remove the
# username, gaining access to all the other users' upload directories.
#
$PREF{url_without_userdir_is_error} = 'yes';
# PREFs Section 04: User-directories.
############################################################################
# If you want per-username upload subdirectories, and you already have some
# kind of login framework in place on your site that stores usernames in
# cookies, then you can use this to automatically choose the right subdir
# based on the value in the cookie. This means that each user will only
# be able to view and upload to his own subdirectory within your
# uploaded_files_dir.
#
$PREF{enable_userdir_from_cookie} = 'no';
$PREF{userdir_cookie_name} = 'username';
# PREFs Section 05: Subdirectories.
############################################################################
# Allow users to upload to subdirectories if they want.
#
$PREF{enable_subdirs} = 'yes';
# PREFs Section 05: Subdirectories.
############################################################################
# Allow users to create new subdirectories (but only within your
# uploaded_files_dir, of course). You can also choose to only
# display a single "New subdir" textbox, even when the user is
# uploading multiple files, so that all the files in that one
# upload session will go into the same new subdirectory.
#
$PREF{enable_new_subdir_creation} = 'yes';
$PREF{only_allow_one_new_subdir_per_upload} = 'no';
$PREF{max_num_of_subdir_levels} = 5;
$PREF{max_length_of_new_subdir_names} = 25;
# PREFs Section 05: Subdirectories.
############################################################################
# If you want to enable subdirectories, but do not want your users to be
# able to see the list of subdirectories on the upload form, then you can
# disable this.
#
$PREF{display_dropdown_box_for_subdir_selection} = 'yes';
# PREFs Section 06: Email Notification.
############################################################################
# You can have the script send you an email whenever a new upload happens.
# It can be sent to as many recipients as you want. Most of the email PREFs
# are fairly self-explanatory, but here are a few notes: the sender address
# doesn't have to be a real address, but it DOES have to end with a real
# domain name. The smtp server is probably localhost or mail.yoursite.com,
# and we'll try both smtp and sendmail when trying to send an email. The
# email type can be either html or text, and the failure action can be
# either die_on_email_error or null, in which case we'll just ignore the
# error. Note that if you set it to die_on_email_error, then that means
# we can't fork the sending operation off into a separate process, since we
# have to wait to make sure it completes; this means that the upload takes
# longer from the user's perspective (if the upload was big and the email-
# sending operation takes a while). So once you've got FileChucker tested
# and are satisfied that the email portion works, you may want to NOT
# die on email error.
#
# SMTP Authentication is only needed if your mail server requires it. If
# so, you'll need to set the path to sendmail to either '/dev/null' or
# just ''.
#
# Note that if you want your users to be able to enter their own email
# address(es) on the upload form, to receive email notifications at those
# addresses, then you must configure a custom text box for that, in
# PREFs Section 07.
#
# If you do enable an email-address textbox, you can choose to have the
# From: address on your notification emails be set to whatever address
# the user enters. To do that, set the $PREF{sender_email_address}
# option here to 'user_email_address'.
#
$PREF{send_email_notifications} = 'no';
$PREF{attach_uploaded_files_to_notification_emails} = 'no';
$PREF{email_notification_recipient_1} = '[email protected]';
$PREF{sender_email_address} = '[email protected]';
$PREF{smtp_server} = 'localhost';
$PREF{smtp_port} = 25; # usually 25 or 587.
$PREF{smtp_auth_username} = '';
$PREF{smtp_auth_password} = '';
$PREF{path_to_sendmail} = '/usr/sbin/sendmail';
$PREF{email_type} = 'html';
$PREF{email_subject} = "New upload on mysite.com";
$PREF{email_failure_action} = 'die_on_email_error';
# PREFs Section 06: Email Notification.
############################################################################
# If you enable a custom text box as an email field (see PREFs Section 07),
# you can choose to have those notification emails contain the uploaded
# files as attachments. Note that this is separate from whether the site's
# webmaster receives attachments on his notification emails (see above).
#
$PREF{attachments_on_notifications_to_userEntered_addresses} = 'no';
# PREFs Section 07: Upload Form Configuration.
############################################################################
# Title appearing at the top of the page.
#
$PREF{title} = '<div id="title">FileChucker</div>';
# PREFs Section 07: Upload Form Configuration.
############################################################################
# Intro: text appearing below the title, before the upload form.
# Outtro: text appearing at the bottom of the form, just before the "Begin
# Upload" button.
#
$PREF{intro} = qq`<p style="text-align: center;">Upload some files!</p>`;
$PREF{outtro} = '';
# PREFs Section 07: Upload Form Configuration.
############################################################################
# If you're embedding FileChucker into an existing layout, then you probably
# want to disable this. In that case you must also put the following lines
# into the <head> section of your website:
#
# <script type="text/javascript" src="/cgi-bin/filechucker.cgi?js"></script>
# <link rel="stylesheet" type="text/css" media="all" href="/cgi-bin/filechucker.cgi?css">
#
$PREF{print_full_html_tags} = 'yes';
# PREFs Section 07: Upload Form Configuration.
############################################################################
# You probably don't want to change these.
#
$PREF{outer_container} = '<div id="fcbody">';
$PREF{perpage_container} = '<div id="%%on_page%%page"><div id="fcc1"><div id="fcc2"><div id="fcc3"><div id="fcc4">';
$PREF{inner_container} = '<div id="fc-container">';
$PREF{inner_container_end} = '</div>';
$PREF{perpage_container_end} = '</div></div></div></div></div>';
$PREF{outer_container_end} = '</div>';
$PREF{print_filefields_wrapper_div} = 'yes';
$PREF{print_file_element_wrapper_div} = 'yes';
$PREF{viewpath_markup_start} = '<div id="viewpath"><div id="viewpath-inner"><div id="viewpath-text">';
$PREF{viewpath_markup_end} = '</div></div></div>';
$PREF{footer_markup_start} = '<div id="fcfooter"><div id="fcfooter-inner"><div id="fcfooter-text">';
$PREF{footer_markup_end} = '</div></div></div>';
# PREFs Section 07: Upload Form Configuration.
############################################################################
# You can adjust the text and the target for the "Home" link that appears
# in the footer.
#
$PREF{home_link_name} = "Home";
$PREF{home_link_url} = "/";
# PREFs Section 07: Upload Form Configuration.
############################################################################
# By default, we print certain footer links (like Home, Upload Files, Show
# Uploads, New Folder, etc) depending on which page we're on (the file-list
# shouldn't have a link to Show Uploads for example, because we're already
# on that page). But if you want, you can override all our footer links by
# specifying your own. Note that there are 4 separate ones, each located
# in its appropriate PREFs section:
#
# custom_footer_for_uploader
# custom_footer_for_uploadcomplete_page
# custom_footer_for_filelist
# custom_footer_for_default_pages (new-folder page, login page, etc)
#
#$PREF{custom_footer_for_uploader} = '<div id="fcfooter"> </div>';
#$PREF{custom_footer_for_default_pages} = '<div id="fcfooter"> </div>';
# PREFs Section 07: Upload Form Configuration.
############################################################################
# By default, if you upload a file that's 1 megabyte or bigger, the file
# sizes and upload rate on the progress bar will be in MB and MB/s. If you
# want to force them to always be in KB instead, set these.
#
$PREF{force_KB_for_size_display} = 'no';
$PREF{force_KB_for_transfer_rate_display} = 'yes';
# PREFs Section 07: Upload Form Configuration.
############################################################################
# Miscellaneous self-explanatory options.
#
$PREF{progress_bar_width} = 350;
$PREF{show_progress_table_during_uploads} = 'yes';
# PREFs Section 07: Upload Form Configuration.
############################################################################
# By default, when an upload begins, the progress bar pops out of nowhere
# and displays below the "Begin Upload" button. If you want, you can set
# this preference so that it clears the rest of the page first, so that the
# progress bar & table are the only thing on the screen during the upload.
#
$PREF{clear_page_during_upload} = 'yes';
# PREFs Section 07: Upload Form Configuration.
############################################################################
# This message is displayed at the end of an upload, before we redirect to
# the "Upload Complete" page.
#
$PREF{server_processing_upload_message} = "Upload complete; the server is now processing your file(s).<br />This could take a minute or two if your upload was very big.<br />Please wait.";
# PREFs Section 07: Upload Form Configuration.
############################################################################
# To cancel an upload, the user only needs to click on some other link, or
# click on one of their Favorites/Bookmarks, or type some other address into
# the browser's address bar, etc. But some users feel more comfortable using
# an explicit "Cancel" link, so if you want to, you can enable such a link
# by setting this PREF. For example:
#
# $PREF{cancelbutton} = '<div><a href="/">Click here to cancel this upload.</a></div>';
#
$PREF{cancelbutton} = '';
# PREFs Section 07: Upload Form Configuration.
############################################################################
# If you want to change the look (style) of FileChucker, you can add your
# own CSS here.
#
$PREF{custom_css_section} = '';
# PREFs Section 07: Upload Form Configuration.
############################################################################
# This is the upload button, in case you want to use an image instead, etc.
#
$PREF{upload_button} = '<div id="uploadbuttonwrapper"><input type="button" value="Begin Upload" id="uploadbutton" onclick="startupload()" /></div>';
# PREFs Section 07: Upload Form Configuration.
############################################################################
# For your custom textboxes (see below), if you choose to make any of them
# required, then if the user does not fill them in, we'll display a message
# and change their colors.
#
$PREF{bgcolor_for_unfilled_required_fields} = '#ffdd00';
$PREF{textcolor_for_unfilled_required_fields} = '#000';
$PREF{default_bgcolor_for_required_fields} = '#ffffff';
$PREF{default_textcolor_for_required_fields} = '#000';
# PREFs Section 07: Upload Form Configuration.
############################################################################
# Custom text boxes (including email address fields & drop-down lists):
#
# Allow the user to enter comments or information about the file(s) that
# they are uploading.
#
# You can specify as many text boxes as you want, and you can put them
# in any of 3 places: the top of the page, the bottom of the page, and/or
# per-file (so if the visitor uploads multiple files at once, the box
# will show up multiple times, once per file). You can also specify
# whether the box should be single-line or multi-line, and for the multi-
# line boxes you can specify the size in pixels. And you can specify
# whether a given text box is saved in a cookie and thus auto-filled the
# next time that visitor loads the page, by setting its _save PREF to yes.
#
# You can also add a _required PREF for any textbox, which will not allow
# the form to be submitted until the user fills that field in.
#
# To make a drop-down list, add an extra PREF ending in _dropdown for the
# textbox in question. Set its value to the list of values you'd like to
# appear in the list, separated by three pipe characters (|||). Note
# that you should probably start the list with the separator too, so that
# it is set to null by default, so that you can use a _required PREF on
# it if you wish, so the user is forced to make a selection.
#
# Finally, note that you can use any textbox as an email address field,
# to which a notification email will be sent, by creating a new PREF for
# that textbox with "_email" on the end (after either _multiline or
# _singleline). For example if you have this:
#
# $PREF{top_textbox_1_singleline} = 'Email Address:';
# $PREF{top_textbox_1_singleline_save} = 'yes';
#
# ...then you can add another PREF like this:
#
# $PREF{top_textbox_1_singleline_email} = 'yes';
#
# Then the textbox will accept 1 or more email addresses separated by
# commas and/or spaces, and notification of the upload including a link
# to the file(s) will be sent to the specified address(es).
#
# You must also enable the send_email_notifications PREF (see PREFs
# Section 06) for this to work.
#
# Note that you should probably only create such an email field if you
# are requiring your users to be logged in before they can upload. This
# is because if you allow just anybody to enter an email address, and you
# then send an email to that address, you have created an open invitation
# for spammers to abuse your website. They can hit it 1000 times per day
# and send their spam to as many addresses as they want.
#
# The following are examples and are commented-out so they won't be used.
# You can uncomment them (delete the "#" at the front of the line) and
# edit them, or create your own.
#
#
#$PREF{top_textboxes_title} = 'Please enter the following information:';
#
#$PREF{top_textbox_1_singleline} = 'Company:';
#$PREF{top_textbox_1_singleline_save} = 'yes';
#$PREF{top_textbox_1_singleline_required} = 'yes';
#$PREF{top_textbox_1_singleline_dbcolname} = 'company';
#
#$PREF{top_textbox_2_multiline} = 'Description of upload:';
#$PREF{top_textbox_2_multiline_save} = 'no';
#$PREF{top_textbox_2_multiline_size} = '200x150';
#
#$PREF{top_textbox_3_singleline} = 'Email Address:';
#$PREF{top_textbox_3_singleline_save} = 'yes';
#$PREF{top_textbox_3_singleline_email} = 'yes';
#$PREF{top_textbox_3_singleline_required} = 'yes';
#
#$PREF{top_textbox_4_singleline} = 'Gender:';
#$PREF{top_textbox_4_singleline_dropdown} = '|||M|||F|||Other';
#$PREF{top_textbox_4_singleline_save} = 'yes';
#$PREF{top_textbox_4_singleline_required} = 'yes';
#
#
#
#$PREF{perfile_textboxes_title} = 'About this file:';
#
#$PREF{perfile_textbox_1_singleline} = 'Created by:';
#$PREF{perfile_textbox_1_singleline_save} = 'no';
#$PREF{perfile_textbox_1_singleline_dbcolname} = 'aboutfile';
#
#$PREF{perfile_textbox_2_singleline} = 'Creation date:';
#$PREF{perfile_textbox_2_singleline_save} = 'no';
#
#$PREF{perfile_textbox_3_multiline} = 'Purpose:';
#$PREF{perfile_textbox_3_multiline_save} = 'no';
#$PREF{perfile_textbox_3_multiline_size} = '180x150';
#
#
#
#$PREF{bottom_textboxes_title} = 'Additional comments (optional):';
#
#$PREF{bottom_textbox_1_multiline} = '';
#$PREF{bottom_textbox_1_multiline_save} = 'no';
#$PREF{bottom_textbox_1_multiline_size} = '200x250';
#$PREF{bottom_textbox_1_multiline_dbcolname} = 'comments';
# PREFs Section 08: Upload Restrictions.
############################################################################
# Allow the user to upload multiple files at the same time, up
# to this limit.
#
$PREF{max_files_allowed} = 5;
# PREFs Section 08: Upload Restrictions.
############################################################################
# Set the maximum amount of data that can be uploaded at once. Note that
# this is per upload, not per file; if you set this to 10 megabytes, then
# you can upload one 10MB file, or two 5MB files, etc, as long as the sum
# is not more than your limit. Note that one megabyte is 1024*1024*1;
# 5 MB is 1024*1024*5, etc.
#
$PREF{sizelimit_for_strangers} = 1024*1024*30;
$PREF{sizelimit_for_members} = 1024*1024*50;
$PREF{sizelimit_for_admins} = 1024*1024*80;
# PREFs Section 08: Upload Restrictions.
############################################################################
# You can allow or disallow uploads based on file extension. Each of these
# two preferences takes a list of extensions separated by commas and/or
# spaces. Note that the period must be included with the extension. For
# example:
#
# $PREF{only_allow_these_file_extensions} = '.jpg, .png, .gif';
#
# Finally, note that these are not case sensitive.
#
$PREF{only_allow_these_file_extensions} = '';
$PREF{disallow_these_file_extensions} = '.php .php3 .php4 .php5 .cgi .pl .sh .py .htaccess .htpasswd';
$PREF{allow_files_without_extensions} = 'yes';
# PREFs Section 08: Upload Restrictions.
############################################################################
# In both filenames and directory names, convert spaces to underscores,
# and remove anything that's not in the set [0-9A-Za-z._-].
#
$PREF{clean_up_filenames} = 'yes';
# PREFs Section 09: Processing Uploads.
############################################################################
# In PREFs Section 03: Security, there is a option "serialize_all_uploads"
# that adds a long (~40 digit) serial number to the end of all filenames.
# But even if that option is disabled, if you don't set the
# overwrite_existing_files option here, then a serial number WILL be
# appended onto the filename if a file by the same name already exists.
# Alternatively, you can set the nice_serialization options here, which
# will add a number like "_01" or " 01" if a file by the same name already
# exists. So in summary, you can have all files serialized (long number),
# all files nice-serialized (2-digit number), only serialize when filename
# already exists (either long or 2-digit serial), or overwrite existing files
# (i.e. never serialize). Note that regular- and nice-serialization are
# mutually exclusive, and that regular (serialize_all_uploads) takes
# precedence if both are set, since it's a security feature.
#
$PREF{overwrite_existing_files} = 'no';
$PREF{nice_serialization_when_file_exists} = 'yes';
$PREF{nice_serialization_always} = 'no';
# PREFs Section 09: Processing Uploads.
############################################################################
# You can have a datestamp (YYYYMMDD-HHMM) added to the filename for
# each upload. It will be added to the end, right before the extension.
#
$PREF{datestamp_all_uploads} = 'no';
# PREFs Section 09: Processing Uploads.
############################################################################
# FileChucker can automatically rename every file that gets uploaded,
# based on a format that you specify here.
#
# You can use the following variables in your filename formatting:
#
# #O - original filename from the user's computer (without extension)
#
# #E - extension from original filename (without leading period)
#
# #U - name of user's private directory (null unless you've
# enabled the userdir PREFs)
#
# #N - sequence number of this file within its original upload
# (set to 1 if only a single file was uploaded)
#
# You can also use variables of the form %v to insert date/time
# values based on the standard date formatting variables; Google for
# "unix man pages: date (1)" (or just run "man date" on any Unix
# system) for more information on the date format.
#
# If you've enabled any custom textboxes (PREFs Section 07), you can
# use the values from those fields in renaming the uploaded files.
# Just use the name of the PREF itself, within a %TEXTBOX container,
# for example:
#
# %TEXTBOX{top_textbox_1_singleline}
# %TEXTBOX{perfile_textbox_4_singleline}
# %TEXTBOX{bottom_textbox_2_singleline}
#
# Finally, you can include variables from either the URL or from a
# cookie by using %URL{varname} or %COOKIE{cookiename}.
#
# And anything not preceded by a pound-sign or a percent-sign will be
# passed straight through as literal text.
#
# For example, if you set:
#
# $PREF{reformat_filenames_for_all_uploads} = '%Y%m%d-#U_#N-%COOKIE{foo}-#O.#E';
#
# ...and then a user uploads 3 files, on say Feb 28 2006, then they
# will be renamed to:
#
# 20060228-userdirname_1-fooCookieValue-originalfilename.ext
# 20060228-userdirname_2-fooCookieValue-originalfilename.ext
# 20060228-userdirname_3-fooCookieValue-originalfilename.ext
#
# Finally note that to disable this, you must comment it out or set
# it to null ('').
#
$PREF{reformat_filenames_for_all_uploads} = '';
# PREFs Section 09: Processing Uploads.
############################################################################
# This setting controls how uploads are processed internally. It should
# probably be set to 'yes' in most cases.
#
$PREF{move_tmpfile_instead_of_copying_contents} = 'yes';
# PREFs Section 09: Processing Uploads.
############################################################################
# You can log information about each uploaded file, like the uploader's
# IP/hostname/user-agent, timestamps, elapsed time, etc. This information
# can be logged in text files and/or in a database.
#
# If you've enabled any custom text boxes, and you have not enabled the
# _in_database PREF here, then the _in_files PREF is automatically enabled.
#
# In order for the store_upload_info_in_database option to work, you must do
# three things:
#
# 1. set the database preferences in PREFs Section 12;
#
# 2. set $PREF{db_columns_for_upload_info} to a comma-separated list
# of the column names that you want to be populated; the names in
# this list must either a) be set by you in PREFs Section 07 under
# "custom textboxes" with a _dbcolname PREF, for example:
#
# $PREF{top_textbox_1_singleline} = 'Please enter your name:';
# $PREF{top_textbox_1_singleline_save} = 'yes';
# $PREF{top_textbox_1_singleline_dbcolname} = 'clientname';
#
# ...or b) be one of the names from the following built-in list of
# upload data collected:
#
# filepath,filename,origpath,origname,filesize,uploadsize,filecount,
# serial,ip,host,userdir,username,useragent,starttime,endtime,
# startetime,endetime,elapsecs,elapmins,elaphours
#
# 3. actually have a database on your server which contains a table
# with the columns specified in $PREF{db_columns_for_upload_info}.
#
# Column types for the built-in list of data collected:
#
# filepath text # because path lengths are unlimited on most FSes.
# filename varchar(255) # because filenames on most FSes are limited to 255 chars.
# origpath text # because path lengths are unlimited on most FSes.
# origname varchar(255) # because filenames on most FSes are limited to 255 chars.
# filesize bigint unsigned # or int, if you're confident your files will never exceed 4 GB.
# uploadsize bigint unsigned # at least as big as "filesize" since a given upload can contain multiple files.
# filecount int unsigned # 4 billion files per upload seems like a reasonable limit.
# serial varchar(80) # pseudo-random number formed by concatenating various sources, usually about 50 chars long. could be longer if your users have lots of digits in their UA strings.
# ip varchar(40) # we'll support IPv6-length IPs just in case.
# host varchar(150) # hostnames can get pretty long.
# userdir varchar(255) # unlikely that a single dirname would exceed this.
# username varchar(255) # unlikely that a single username would exceed this.
# useragent varchar(255) # my Firefox 1.5.0.4 UA is 105 chars.
# starttime varchar(22) # format is "WedJul26,2006,09:38pm".
# endtime varchar(22) # format is "WedJul26,2006,09:38pm".
# startetime bigint unsigned # the current epoch-time value is around 1.1 billion; ~2 billion is the year 2035; INT's limit is about 4 billion, so BIGINT to be safe.
# endetime bigint unsigned # the current epoch-time value is around 1.1 billion; ~2 billion is the year 2035; INT's limit is about 4 billion, so BIGINT to be safe.
# elapsecs int unsigned # unlikely for a single upload to need/exceed 4 billion seconds (1 million hours).
# elapmins float unsigned # a simple decimal number with a single digit after the decimal.
# elaphours float unsigned # a simple decimal number with a single digit after the decimal.
#
# And of course your table should have an id column of type:
# BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY.
#
# Here's the SQL code to create that table:
#
# CREATE TABLE `upload_info` (
# `id` BIGINT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY ,
# `filepath` TEXT NOT NULL ,
# `filename` VARCHAR( 255 ) NOT NULL ,
# `origpath` TEXT NOT NULL ,
# `origname` VARCHAR( 255 ) NOT NULL ,
# `filesize` BIGINT UNSIGNED NOT NULL ,
# `uploadsize` BIGINT UNSIGNED NOT NULL ,
# `filecount` INT UNSIGNED NOT NULL ,
# `serial` VARCHAR( 80 ) NOT NULL ,
# `ip` VARCHAR( 40 ) NOT NULL ,
# `host` VARCHAR( 150 ) NOT NULL ,
# `userdir` VARCHAR( 255 ) NOT NULL ,
# `username` VARCHAR( 255 ) NOT NULL ,
# `useragent` VARCHAR( 255 ) NOT NULL ,
# `starttime` VARCHAR( 22 ) NOT NULL ,
# `endtime` VARCHAR( 22 ) NOT NULL ,
# `startetime` BIGINT UNSIGNED NOT NULL ,
# `endetime` BIGINT UNSIGNED NOT NULL ,
# `elapsecs` INT UNSIGNED NOT NULL ,
# `elapmins` FLOAT UNSIGNED NOT NULL ,
# `elaphours` FLOAT UNSIGNED NOT NULL
# ) ENGINE = MYISAM ;
#
# Finally note that each row in the database represents one uploaded file,
# not one upload session. Unless of course you've configured FileChucker
# to only allow one file to be uploaded at a time, in which case there IS
# only one uploaded file in one upload session.
#
$PREF{store_upload_info_in_files} = 'yes';
$PREF{store_upload_info_in_database} = 'no';
$PREF{db_table_for_upload_info} = 'upload_info';
$PREF{db_columns_for_upload_info} = 'filepath,filename,origpath,origname,filesize,uploadsize,filecount,serial,ip,host,userdir,username,useragent,starttime,endtime,startetime,endetime,elapsecs,elapmins,elaphours';
# PREFs Section 10: Post-Upload.
############################################################################
# After a successful upload, we normally display a page that says
# "upload complete" and lists the uploaded files, their sizes, etc.
# If you want, you can redirect to some other page instead. This
# value MUST start with http:// or https://. Note that you can include
# variables in the value from either the URL or from a cookie by
# using %URL{varname} or %COOKIE{cookiename}. For example:
#
# $PREF{after_upload_redirect_to} = 'http://mysite.com/foo/bar/?baz=%URL{baz}&bim=%COOKIE{bim}';
#
# Finally, note that you can set pass_filenames_on_redirect to get the list
# of names, paths, and sizes of the uploaded files.
#
$PREF{after_upload_redirect_to} = '';
$PREF{pass_filenames_on_redirect} = 'yes';
$PREF{pass_textbox_values_on_redirect} = 'yes';
$PREF{pass_original_querystring_through} = 'yes';
# PREFs Section 10: Post-Upload.
############################################################################
# On the "upload complete" page, we'll print "File X of Y:" followed by
# the filename as a link to the file. But if you want the full URL of the
# link to be displayed as text on the page, you can enable this option.
#
$PREF{show_text_url_to_file_after_upload} = 'no';
# PREFs Section 10: Post-Upload.
############################################################################
# Choose what is displayed on the "Upload Complete" page.
#
$PREF{show_builtin_upload_complete_message} = 'yes';
$PREF{show_builtin_stats_on_upload_complete_page} = 'yes';
$PREF{custom_message_for_upload_complete_page} = '';
# PREFs Section 10: Post-Upload.
############################################################################
# By default, we print certain footer links (like Home, Upload Files, Show
# Uploads, New Folder, etc) depending on which page we're on (the file-list
# shouldn't have a link to Show Uploads for example, because we're already
# on that page). But if you want, you can override all our footer links by
# specifying your own. Note that there are 4 separate ones, each located
# in its appropriate PREFs section:
#
# custom_footer_for_uploader
# custom_footer_for_uploadcomplete_page
# custom_footer_for_filelist
# custom_footer_for_default_pages (new-folder page, login page, etc)
#
#$PREF{custom_footer_for_uploadcomplete_page} = '<div id="fcfooter"> </div>';
# PREFs Section 11: File-List Configuration.
############################################################################
# Options for controlling the display of the uploaded-files list.
# You can set the unit, number of decimal places, and the color
# that the rows turn to when you hover the mouse over them. You
# can also specify how the date should be displayed. Google for
# "unix man pages: date (1)" (or just run "man date" on any Unix
# system) for more information on the date format.
#
$PREF{unit_for_size_display_in_uploaded_files_list} = 'KB'; # must be 'KB', 'MB', or 'mixed'. See PREFs Section Z if you want Ko/Mo.
$PREF{num_decimals_for_uploaded_files_list_sizes} = 0;
$PREF{display_shortened_filename_if_longer_than} = 35; # characters.
#$PREF{filelist_row_hover_border} = '1px solid #bbb'; # currently in testing.
#$PREF{filelist_row_normal_border} = '1px solid white'; # currently in testing.
$PREF{date_format_for_filelist} = '%b%d, %I:%M%P';
#$PREF{date_format_for_filelist} = '%Y-%m-%d, %I:%M %P';
#$PREF{date_format_for_filelist} = '%a %b %d, %Y, %H:%M';
#$PREF{date_format_for_filelist} = '%I:%M %P %b %d %Y';
$PREF{only_show_files_with_these_extensions} = '';
$PREF{hide_files_with_these_extensions} = '.php .php3 .php4 .php5 .cgi .pl .sh .py .htaccess .htpasswd';
$PREF{time_offset} = -0; # in hours; can include negative sign.
# PREFs Section 11: File-List Configuration.
############################################################################
# File-list styling. Set the color the rows change to on mouse-over (and
# on mouse-out); choose the default file-list style and whether to display
# a link in the footer to switch between the styles. You can also create
# your own styles here by adding the name of your new style to the list in
# the enabled_styles PREF, adding a block of corresponding PREFs for it
# here, and then adding a section for it within the get_css() subroutine.
#
$PREF{default_filelist_style} = 'light';
$PREF{enable_filelist_style_switcher_link} = 'yes';
$PREF{enabled_styles} = 'round, light, dark, big';
$PREF{round___filelist_row_hover_bgcolor} = '#c0c2b9';
$PREF{round___filelist_row_hover_bgcolor_highcontrast} = '#86a9bc';
$PREF{round___filelist_row_normal_bgcolor_even} = '#efefef';
$PREF{round___filelist_row_normal_bgcolor_odd} = '#efefef';
$PREF{round___filelist_row_hover_text_color} = 'white';
$PREF{round___filelist_row_hover_link_color} = 'white';
$PREF{round___filelist_row_normal_text_color} = '#444';
$PREF{round___filelist_row_normal_link_color} = '#444';
$PREF{round___filelist_row_visited_link_color} = '#444';
$PREF{light___filelist_row_hover_bgcolor} = '#c0c2b9';
$PREF{light___filelist_row_hover_bgcolor_highcontrast} = '#507090';
$PREF{light___filelist_row_normal_bgcolor_even} = '#efefef';
$PREF{light___filelist_row_normal_bgcolor_odd} = '#e6e6e6';
$PREF{light___filelist_row_hover_text_color} = 'white';
$PREF{light___filelist_row_hover_link_color} = 'white';
$PREF{light___filelist_row_normal_text_color} = 'black';
$PREF{light___filelist_row_normal_link_color} = 'black';
$PREF{light___filelist_row_visited_link_color} = 'black';
$PREF{dark___filelist_row_hover_bgcolor} = '#474747';
$PREF{dark___filelist_row_normal_bgcolor_even} = '#545454';
$PREF{dark___filelist_row_normal_bgcolor_odd} = '#545454';
$PREF{dark___filelist_row_hover_text_color} = 'white';
$PREF{dark___filelist_row_hover_link_color} = '#000';
$PREF{dark___filelist_row_normal_text_color} = '#fff';
$PREF{dark___filelist_row_normal_link_color} = '#fff';
$PREF{dark___filelist_row_visited_link_color} = '#fff';
$PREF{darker___filelist_row_hover_bgcolor} = '#4a774a';
$PREF{darker___filelist_row_normal_bgcolor_even} = '#545454';
$PREF{darker___filelist_row_normal_bgcolor_odd} = '#4d4d4d';
$PREF{darker___filelist_row_hover_text_color} = 'white';
$PREF{darker___filelist_row_hover_link_color} = 'white';
$PREF{darker___filelist_row_normal_text_color} = '#fff';
$PREF{darker___filelist_row_normal_link_color} = '#fff';
$PREF{darker___filelist_row_visited_link_color} = '#fff';
$PREF{big___filelist_row_hover_bgcolor} = '#507090';
$PREF{big___filelist_row_hover_bgcolor_highcontrast} = '#507090';
$PREF{big___filelist_row_normal_bgcolor_even} = '#efefef';
$PREF{big___filelist_row_normal_bgcolor_odd} = '#e6e6e6';
$PREF{big___filelist_row_hover_text_color} = 'black';
$PREF{big___filelist_row_hover_link_color} = 'black';
$PREF{big___filelist_row_normal_text_color} = 'black';
$PREF{big___filelist_row_normal_link_color} = 'black';
$PREF{big___filelist_row_visited_link_color} = 'black';
$PREF{minimal___filelist_row_hover_bgcolor} = '#a3a3a3';
$PREF{minimal___filelist_row_normal_bgcolor_even} = '#fff';
$PREF{minimal___filelist_row_normal_bgcolor_odd} = '#fff';
$PREF{minimal___filelist_row_hover_text_color} = 'black';
$PREF{minimal___filelist_row_hover_link_color} = 'black';
$PREF{minimal___filelist_row_normal_text_color} = 'black';
$PREF{minimal___filelist_row_normal_link_color} = 'black';
$PREF{minimal___filelist_row_visited_link_color} = 'black';
# PREFs Section 11: File-List Configuration.
############################################################################
# By default, we print certain footer links (like Home, Upload Files, Show
# Uploads, New Folder, etc) depending on which page we're on (the file-list
# shouldn't have a link to Show Uploads for example, because we're already
# on that page). But if you want, you can override all our footer links by
# specifying your own. Note that there are 4 separate ones, each located
# in its appropriate PREFs section:
#
# custom_footer_for_uploader
# custom_footer_for_uploadcomplete_page
# custom_footer_for_filelist
# custom_footer_for_default_pages (new-folder page, login page, etc)
#
#$PREF{custom_footer_for_filelist} = '<div id="fcfooter"> </div>';
# PREFs Section 11: File-List Configuration.
############################################################################
# The links to download files can either be normal HTML links that go
# directly to the file:
#
# <a href="/path/to/uploads/blah/myfile.foo">myfile.foo</a>
#
# ...or, they can go through FileChucker:
#
# <a href="/upload/?action=download&path=blah&file=myfile.foo">myfile.foo</a>
#
# If the links go through FileChucker, then you can password-protect them
# (via the PREFs must_be_admin_to_download and must_be_member_to_download)
# and you can also choose to receive an email notification whenever a file
# is downloaded (TODO).
#
# Note that the download_links_go_through_FileChucker option is mutually
# exclusive with the download_links_go_through_PeerFactor option.
#
# If you want the file's timestamp to be updated (to indicate that the file
# was accessed) when it is downloaded, you can enable that option. Note
# that this is only possible when download_links_go_through_FileChucker is
# enabled.
#
$PREF{download_links_go_through_FileChucker} = 'no';
$PREF{update_timestamp_on_download} = 'yes';
# PREFs Section 11: File-List Configuration.
############################################################################
# You can choose to have your download links go through PeerFactor, which
# is a P2P-based automatic load-balancing system. All the links in your
# file-list will get prefixed with:
#
# http://www.peerfactor.fr/get_myfile.jsp?URL=
#
# When a user clicks on a download link, he will receive the file from the
# PeerFactor P2P network if demand for that file is high, or else he'll get
# the file directly from your server if demand for the file is low. The
# PeerFactor site determines demand in real-time so this is all transparent
# to the user.
#
# Note that the download_links_go_through_PeerFactor option is mutually
# exclusive with the download_links_go_through_FileChucker option.
#
$PREF{download_links_go_through_PeerFactor} = 'no';
# PREFs Section 11: File-List Configuration.
############################################################################
# You can choose to have FileChucker automatically delete files older than
# a set number of hours. Set the old_file_ttl (time-to-live) to the age (in
# hours) at which you'd like old files to get deleted. In order to delete
# old files, we need to check the age of all the files every N hours or
# minutes. You can choose to make this check happen daily (at a certain
# hour/hours) or hourly (at a certain minute/minutes). For the lists of
# hours/minutes at which to check, the numbers must be separated by commas
# and/or spaces.
#
# Note that a file's date/timestamp is only updated when the file is
# created or modified; it is NOT updated when the file is simply accessed
# (i.e. by being downloaded). If you want the date/timestamps to get
# updated upon download, then you must set update_timestamp_on_download
# and download_links_go_through_FileChucker, both of which are in PREFs
# Section 11.
#
# Finally, note that in order for this to work, the script must actually be
# running at the hour(s) or minute(s) that you specify, i.e. someone must
# happen to be either uploading a file at that time, or viewing the file-
# list at that time. So if your FileChucker installation doesn't get very
# many visitors, you will probably want to use the "check_daily" option
# instead of the "check_hourly" one, and you'll want to specify a bunch of
# different hours at which to check. For example, you could list every
# hour from 0 to 23 (and enable "check_daily_for_old_files") to cause
# FileChucker to perform this check every single time it runs. Of course
# on servers with lots of traffic, you wouldn't want to run the check
# that often.
#
$PREF{automatically_delete_old_files} = 'no';
$PREF{old_file_ttl} = '168'; # in hours.
$PREF{check_daily_for_old_files} = 'yes';
$PREF{hours_at_which_to_check} = '0,12'; # can be from 0 to 23.
$PREF{check_hourly_for_old_files} = 'no';
$PREF{minutes_at_which_to_check} = '0,15,30,45'; # can be from 0 to 59.
# PREFs Section 11: File-List Configuration.
############################################################################
# Shopping cart / ordering system: you can enable a very basic ordering
# system, where your users can select items (files) from your upload area
# and add them to their cart, and they can then place an order for those
# items, which simply sends an email to you, containing their user info
# and the list of items that they selected. Note that you must configure
# the SMTP settings in PREFs Section 06 for this to work.
#
$PREF{enable_ordering} = 'no';
$PREF{select_item_link} = '<span style="white-space: nowrap; font-size: 80%;">Add To Cart</span>';
$PREF{selection_cookie_name} = 'selected_items';
$PREF{clear_selections_text} = 'Empty Cart';
$PREF{clear_selections_verification_text} = 'About to empty your cart. Is that OK?';
$PREF{no_selections_text} = 'Your cart is empty.';
$PREF{duplicate_item_text} = 'This item is already in your cart. Add it again?';
$PREF{view_items_page_name} = 'Your Cart';
$PREF{view_items_page_intro} = '<h1>Your Cart</h1><p>Your cart contains the following items. Use the Submit<br />button below when you are ready to checkout.</p>';
$PREF{place_order_fields} = '<div class="name"><input type="text" name="name" class="text required" /> Name</div> <div class="email"><input type="text" name="email" class="text required" /> Email</div> <div class="submit"><input type="button" value="Submit Your Order" onclick="startorder()" /></div> ';
$PREF{process_order_page_name} = 'Order Received - Thank You';
$PREF{process_order_page_intro} = '<h1>Order Received</h1><p>Thank you for your order. We are now processing it and we will <br />contact you soon. Please print or save this page for your records.</p>';
$PREF{order_email_recipient_1} = '[email protected]';
$PREF{order_sender_email_address} = '[email protected]';
$PREF{order_email_subject} = 'Order Received';
$PREF{order_email_top_intro} = '<h1>Order Received:</h1>';
$PREF{order_email_items_intro} = '<h2>Items Ordered:</h2>';
$PREF{order_email_user_intro} = '<h2>User Information:</h2>';
$PREF{send_copy_to_userEntered_email_address} = 'yes';
# PREFs Section 12: Database Setup.
############################################################################
# If you're using any FileChucker features that require a database, then
# you'll need to configure it here. The database name can optionally have
# a :hostname after the database-name. Here are two commented-out examples
# for reference:
#
# $PREF{dbname} = 'mydbname';
# $PREF{dbname} = 'mydbname:mydbhost';
#
# The database username needs at least the INSERT and SELECT privileges, but
# depending on which DB-related PREFs you're using, it may need other privs
# too (see that particular PREF for the details).
#
$PREF{dbname} = '';
$PREF{dbuser} = '';
$PREF{dbpass} = '';
# PREFs Section Z: Misc Settings Not Usually Needed.
############################################################################
# By default, if your server's version of the CGI.pm module is >= 3.03,
# then we'll use its upload hook. If it's older than 3.03, we'll do it
# manually, since older versions don't support the upload hook. This
# means we can't show the counts for number of files completed/remaining,
# but if your server has an ancient version of the CGI.pm module, then
# you have no choice. Anyway, this PREF is in case the script isn't
# working for you, even though you DO have v3.03 or newer. Setting this
# to 'yes' will force the manual behavior, and the only loss will be the
# aforementioned files-completed/files-remaining; the time and size will
# still display properly.
#
$PREF{disable_upload_hook} = 'no';
# PREFs Section Z: Misc Settings Not Usually Needed.
############################################################################
# FileChucker can use a database backend instead of diskfiles to store
# its temporary working data, if you'd like. There's really no benefit
# of one method over the other (and on servers that perform write-caching,
# thus preventing the progress bar from working properly, the database
# backend doesn't actually work around the problem, as we had thought it
# might).
#
# For this to work, your database username (in PREFs Section 12) needs
# privileges for INSERT, UPDATE, SELECT, DELETE, and CREATE. If you're
# paranoid and don't want to give it CREATE privs, then see the
# create_db_table_for_temp_data() function to find out the column types,
# so you can create the table manually.
#
$PREF{use_database_for_temp_data} = 'no';
$PREF{table_name_for_temp_data} = 'temp_upload_data';
# PREFs Section Z: Misc Settings Not Usually Needed.
############################################################################
# You probably don't want the temp-data entries filling up your DB since
# they don't actually contain any useful information after the upload is
# complete. But you can disable this if for some reason you want them kept.
# Note that this doesn't delete the uploaded files; they aren't stored in
# the database.
#
$PREF{purge_temp_data_immediately} = 'yes';
# PREFs Section Z: Misc Settings Not Usually Needed.
############################################################################
# If you're using FileChucker in a way where it doesn't make sense for the
# default page to be the uploader, you can change that here. Currently the
# options are 'uploader' and 'filelist'.
#
$PREF{default_page} = 'uploader';
# PREFs Section Z: Misc Settings Not Usually Needed.
############################################################################
# If you want to use Ko instead of KB, etc, you can set those labels here.
# Note that you should not change these to Kb or Mb, since lowercase-b means
# "bit", not "byte", so all the displayed values would be incorrect.
#
$PREF{KB} = 'KB';
$PREF{MB} = 'MB';
# PREFs Section Z: Misc Settings Not Usually Needed.
############################################################################
# Specify the length of the serial number and whether it should be all
# numbers or can also contain letters. A length less than 10 is NOT a
# good idea because the smaller the value, the better the chance that
# there will be collisions between simultaneous uploads. But even 10
# is pretty low; 20 is better, and 30 is the default.
#
$PREF{length_of_serial} = 30;
$PREF{use_letters_in_serial} = 'yes';
############################################################################
###
### End of user preferences section. You probably don't want to mess with
### anything below here unless you really know what you're doing.
###
############################################################################
$| = 1;
use strict;
#use warnings;
if($PREF{show_errors_in_browser} =~ /yes/i)
{
use CGI::Carp 'fatalsToBrowser';
}
use Fcntl;
use CGI;
use POSIX;
use CGI qw/:standard/;
eval { require DBI; }; die "$0: $@\n" if $@ && ($PREF{use_database_for_temp_data} =~ /yes/i || $PREF{store_upload_info_in_database} =~ /yes/i);
# Set globals. TODO: some of these need to be re-scoped.
my ($qs, $starttime, $total_upload_size, $errorlogfh, %temp, $num_files_in_progress_or_done, $total_file_count, $dbh, $ampm, $shortdatetime, $shortdatetime_forfilename, $datestring8) = ();
load_prefs();
if($qs =~ /serial=([0-9a-zA-Z]+)&action=get_progress_and_size/)
{
print "Cache-Control: no-store, no-cache\n";
print "Content-type: text/xml\n\n";
my ($progress,$currentfile,$totalfiles,$size,$elapsedtime) = get_progress_and_size($1);
if($progress eq 'ENOLOG')
{
print "ERROR: the log file hasn't been created yet; probably your server is doing some write-caching so the log doesn't get created when we create it -- it actually gets created AFTER the upload is complete, making progress reporting impossible.";
exit;
}
elsif($progress eq 'ENORAWPOST')
{
print "ERROR: the rawpost file hasn't been created yet; probably your server is doing some write-caching so the file doesn't get created when we create it -- it actually gets created AFTER the upload is complete, making progress reporting impossible.";
exit;
}
my $toobig = $size > $CGI::POST_MAX ? '|toobig' : '';
my $finished_file_count = $currentfile ? $currentfile - 1 : 0;
my $output = "$progress|$size|$elapsedtime|$finished_file_count|$total_file_count" . $toobig;
print qq`<?xml version="1.0" encoding="ISO-8859-1"?>\n<progress>\n<data>`;
#print qq`<?xml version="1.0" encoding="UTF-8"?>\n<progress>\n<data>`;
print $output;
print qq`</data>\n</progress>\n`;
}
elsif($qs =~ /(?:^|&)action=uploadcomplete(?:&|$)/)
{
show_uploadcomplete_page();
}
elsif($qs =~ /(?:^|&)action=view_items(?:&|$)/)
{
view_items();
}
elsif($qs =~ /(?:^|&)action=process_order(?:&|$)/)
{
process_order();
}
elsif($qs =~ /(?:^|&)action=order_confirmation(?:&|$)/)
{
order_confirmation();
}
elsif($qs =~ /(?:^|&)action=loggedout&whence=(.*)(?:&|$)/)
{
# note that the whence regex is .* not .*? because the value
# will likely contain ampersands that we want to keep.
show_loggedout_page($1);
}
#elsif($qs eq 'get_logo')
#{
# my $logo = get_logo();
# print "Content-type: image/png\n";
# print "Content-transfer-encoding: binary\n\n";
# print `uudecode -o /dev/stdout $logo`;
#}
elsif($qs =~ /action=delete(?:&path=(.*?))?&(file|dir)=(.+?)(&really=yes)?(?:&|$)/)
{
delete_item($1,$2,$3,$4);
}
elsif($qs =~ /action=(move|rename)&(file|folder)=(.+?)&src=(.*?)(?:&dst=(.+?))?(?:&|$)/)
{
move_item($1,$2,$3,$4,$5);
}
elsif($qs =~ /action=fileinfo&path=(.*?)&file=(.+?)(?:&|$)/)
{
show_fileinfo($1, $2);
}
elsif($qs =~ /action=download&path=(.*?)&file=(.+?)(?:&|$)/)
{
download_file($1, $2);
}
elsif($qs =~ /action=mkdir(?:&path=(.+?)(?:&dirname=(.+))?)?(?:&|$)/)
{
make_dir($1,$2);
}
elsif($ENV{REQUEST_METHOD} =~ /post/i)
{
process_upload();
}
elsif($qs =~ /(?:^|&)action=listfiles(?:&|$)/)
{
list_uploaded_files();
}
elsif($qs =~ /(?:^|&)action=upload(?:&|$)/)
{
print_new_upload_form();
}
else
{
if($PREF{default_page} eq 'filelist')
{
list_uploaded_files();
}
else
{
print_new_upload_form();
}
}
sub print_new_upload_form()
{
unless(user_is_allowed_to('upload')) { print_needlogin_error_and_exit('upload'); }
$PREF{on_page} = 'uploader';
start_html_output('Upload a file', 'css', 'js');
my $numitems = $qs =~ /(?:^|&)items=(\d+)(?:&|$)/ ? $1 : 1;
$numitems = 1 if $numitems > $PREF{max_files_allowed};
# The onsubmit() in this <form> is only fired when someone presses Enter when a textbox is focused. The upload button has its own call to onsubmit().
print qq`<form name="theuploadform" id="theuploadform" method="post" enctype="multipart/form-data" action="$ENV{SCRIPT_NAME}?` . ($qs ? "$qs&" : undef) . qq`serial=$PREF{serial}" onsubmit="return startupload()">\n\n`;
print qq`<div id="intro">$PREF{intro}</div>\n\n` if $PREF{intro};
if($PREF{max_files_allowed} > 1)
{
print qq`<div id="setfilecount">Number of files to upload: \n<select name="itemcount" id="itemcount">\n`;
for(my $j=1; $j<=$PREF{max_files_allowed}; $j++)
{
print qq`\n<option value="$j" ` . ($j == $numitems ? qq` selected="selected"` : '') . qq`>$j</option>`;
}
print qq`\n</select>\n <input type="button" class="defaultbutton" name="updateformfields" value="Apply" onclick="update_form_fields()" />\n</div>\n\n\n\n`;
}
my $top_textboxes = get_textboxes('top');
print qq`$top_textboxes\n\n\n\n` if $top_textboxes;
print qq`<div id="filefields">\n` if $PREF{print_filefields_wrapper_div} =~ /yes/i;
my $tab = "\t" if $PREF{print_filefields_wrapper_div} =~ /yes/i;
my @dirs = sort { lc($a) cmp lc($b) } ( get_all_subdirs($PREF{uploaded_files_realpath}) );
for(my $i=1; $i<=$numitems; $i++)
{
my $row = ($i % 2) ? 'odd' : 'even';
print qq`$tab<div class="$row onesubgroup">`;
print qq`<div class="fileelement">` if $PREF{print_file_element_wrapper_div} =~ /yes/i;
print qq`<label for="uploadname$i">` . ($PREF{max_files_allowed} > 1 ? "File $i of $numitems:" : "File:") . qq`</label> <input class="file` . ($i == 1 ? ' required' : undef) . qq`" type="file" name="uploadname$i" id="uploadname$i" $PREF{filefield_size} />`;
print qq`</div>` if $PREF{print_file_element_wrapper_div} =~ /yes/i;
if($PREF{enable_subdirs} =~ /yes/i)
{
if($PREF{display_dropdown_box_for_subdir_selection} =~ /yes/i)
{
print qq`\n$tab<div>Upload to: <select name="subdir$i">`;
print qq`\n$tab<option value="/">` . (get_uploaded_files_url_path('without_trailing_slash')) . qq`/</option>\n`;
for(@dirs)
{
print qq`\n$tab<option value="/$_/">` . (get_uploaded_files_url_path('without_trailing_slash')) . qq`/$_/</option>\n`;
}
print qq`\n$tab</select></div>`;
}
else
{
print qq`\n$tab<input type="hidden" name="subdir$i" value="/" />`;
}
if($PREF{enable_new_subdir_creation} =~ /yes/i)
{
unless($PREF{only_allow_one_new_subdir_per_upload} =~ /yes/i && $i > 1)
{
my $newsubdir_instructions = $PREF{display_dropdown_box_for_subdir_selection} =~ /yes/i ? qq`\n$tab<div>(will be created inside the selected directory)</div>` : undef;
print qq`\n$tab<div>New subdirectory? Name: <input type="text" class="default text" name="newsubdir$i" maxlength="$PREF{max_length_of_new_subdir_names}" /></div>$newsubdir_instructions`;
}
}
print qq`\n$tab`;
}
my $perfile_textboxes = get_textboxes('perfile', $i);
print $perfile_textboxes;
print qq`</div>\n`;
}
print qq`</div>\n\n\n\n` if $PREF{print_filefields_wrapper_div} =~ /yes/i;
my $bottom_textboxes = get_textboxes('bottom');
print $bottom_textboxes;
print qq`<div id="outtro">$PREF{outtro}</div>\n\n\n\n` if $PREF{outtro};
print qq`
<input type="hidden" name="numitems" id="numitems" value="$numitems" />
<input type="hidden" name="numfileelements" id="numfileelements" value="$numitems" />
$PREF{upload_button}
</form>
<div id="progBarContainer" style="position: absolute; left: -10000px; overflow: hidden; height: 0;">
<div id="theMeter">
<div id="progBar">
<div id="progBarDone"></div>
</div>
<div id="progBarText">
<div id="progRate">? KB/s</div>
<div id="progStatus">Connecting; please wait.</div>
<div id="progPercent">? %</div>
<div class="clear"> </div>
</div>
</div>
<div id="uploadCompleteMsg" style="position: absolute; left: -10000px; overflow: hidden; height: 0;"></div>
` . ($PREF{show_progress_table_during_uploads} =~ /yes/i ? qq`
<table>
<tr id="upload-row-1"><td id="tca1"></td><td id="tca2" class="headercell">Files</td><td id="tca3" class="headercell">Size</td><td id="tca4" class="headercell">Time</td></tr>
<tr id="upload-row-2"><td id="tcb1" class="headercell">Total</td> <td id="totalf">$total_file_count</td> <td id="totals">?</td> <td id="totalt">??:??:??</td></tr>
<tr id="upload-row-3"><td id="tcc1" class="headercell">Completed</td> <td id="donef">0</td> <td id="dones">0</td> <td id="donet">00:00:00</td></tr>
<tr id="upload-row-4"><td id="tcd1" class="headercell">Remaining</td> <td id="leftf">$total_file_count</td> <td id="lefts">?</td> <td id="leftt">??:??:??</td></tr>
</table>
` : undef) . qq`
$PREF{cancelbutton}
</div>
<div id="debug"></div>
`;
print_footer_links('home', 'list', 'logout', 'login', 'styleswitch', 'pb');
finish_html_output();
delete_old_files();
}
sub hook
{
my ($current_filename, $buffer, $bytes_read, $logfh) = @_;
my $current_file_has_been_logged = 0;
my ($progress,$currentfile,$totalfiles,$totalsize,$start_time) = ();
my $serial = $PREF{serial};
my @logcontents = ();
# We're still the original process that's accepting the upload, so
# we don't need to ask the backend for this now, we can store it
# in a hash for easier retrieval:
#
$progress = $PREF{uploaddata}{$serial}{progress};
$currentfile = $PREF{uploaddata}{$serial}{currentfile};
$totalfiles = $PREF{uploaddata}{$serial}{totalfiles};
$totalsize = $PREF{uploaddata}{$serial}{totalsize};
$start_time = $PREF{uploaddata}{$serial}{start_time};
# There are three possibilities here:
#
# 1. $current_filename has already been logged (i.e. it's in @allfiles)
# and its size has either gone up, or stayed the same;
#
# 2. $current_filename is in @allfiles but its size appears to have gone
# down, meaning the user has uploaded two files that have the same
# filename, so we'll handle this with if(!$current_file_has_been_logged);
#
# 3. $current_filename is NOT in @allfiles, which we'll also handle with
# if(!$current_filename_has_been_logged).
my $new_progress = ();
my (@allfiles) = split(m!///!, $progress);
for(@allfiles)
{
if(/(.+)=(\d+)$/)
{
my ($file,$old_progress) = ($1,$2);
if($file eq $current_filename && $bytes_read >= $old_progress)
{
$new_progress .= "${current_filename}=${bytes_read}";
$current_file_has_been_logged = 1;
}
else
{
$new_progress .= "${file}=${old_progress}";
}
$new_progress .= "///";
}
}
if(!$current_file_has_been_logged)
{
unless(!$current_filename || $bytes_read !~ /^\d+$/)
{
$new_progress .= "${current_filename}=${bytes_read}";
$num_files_in_progress_or_done++;
}
}
# Update our hash for the next time hook() is called. We'll still update
# the backend below, so the client can get the info too.
#
$PREF{uploaddata}{$serial}{progress} = $new_progress;
$PREF{uploaddata}{$serial}{currentfile} = $num_files_in_progress_or_done;
$PREF{uploaddata}{$serial}{totalfiles} = $total_file_count;
$PREF{uploaddata}{$serial}{totalsize} = $total_upload_size;
$PREF{uploaddata}{$serial}{start_time} = $starttime;
if($PREF{use_database_for_temp_data} =~ /yes/i)
{
my $sth = $dbh->prepare("UPDATE $PREF{table_name_for_temp_data} SET progress='$new_progress', currentfile='$num_files_in_progress_or_done', totalfiles='$total_file_count', totalsize='$total_upload_size', start_time='$starttime' WHERE serial='$PREF{serial}';");
$sth->execute or die "$0: $DBI::errstr\n";
}
elsif($PREF{use_single_log_backend} =~ /yes/i)
{
my $updated_line = "${serial}:|:${new_progress}:|:${num_files_in_progress_or_done}:|:${total_file_count}:|:${total_upload_size}:|:${starttime}\n";
#print STDERR "hook(): writing updated line: $updated_line";
seek $logfh, 0, 0; # seek to the beginning again, before we start writing.
print $logfh @logcontents;
print $logfh $updated_line;
truncate $logfh, tell $logfh; # truncate the file (on the off chance that the new size is less than the old)
flock $logfh, 8; # release the lock
}
else
{
seek $logfh, 0, 0; # seek to the beginning again, before we start writing.
print $logfh "${new_progress}:|:${num_files_in_progress_or_done}:|:${total_file_count}:|:${total_upload_size}:|:${starttime}\n"; # print the static info
truncate $logfh, tell $logfh; # truncate the file (on the off chance that the new size is less than the old)
flock $logfh, 8; # release the lock
}
}
sub get_progress_and_size
{
printd(qq`starting get_progress_and_size()\n`);
unless(user_is_allowed_to('upload')) { print_needlogin_error_and_exit('upload'); }
my $serial = shift;
$serial = enc_untaint($serial);
my ($progress,$currentfile,$totalfiles,$totalprogress,$totalsize,$start_time,$elapsedtime) = ();
if($PREF{using_upload_hook})
{
if($PREF{use_database_for_temp_data} =~ /yes/i)
{
my $sth = $dbh->prepare("SELECT progress,currentfile,totalfiles,totalsize,start_time FROM $PREF{table_name_for_temp_data} WHERE serial='$serial';");
$sth->execute;
($progress,$currentfile,$totalfiles,$totalsize,$start_time) = $sth->fetchrow;
}
elsif($PREF{use_single_log_backend} =~ /yes/i)
{
my $logfile = "$PREF{datadir}/log.log";
open(READLOGFILE,"<$logfile") or die "$0: couldn't open $logfile for reading: $!\n";
flock READLOGFILE, 1;
seek READLOGFILE, 0, 0;
while(<READLOGFILE>)
{
chomp;
if(/^${serial}:|:(\d+):|:(\d+):|:(\d+):|:(\d+):|:(\d+)$/)
{
($progress,$currentfile,$totalfiles,$totalsize,$start_time) = ($1,$2,$3,$4,$5);
last;
}
}
close READLOGFILE or die "$0: couldn't close $logfile after reading: $!\n";
}
else
{
my $logfile = "$PREF{datadir}/$serial.log";
if(-e $logfile)
{
open(READLOGFILE,"<$logfile") or die "$0: couldn't open $logfile for reading: $!\n";
flock READLOGFILE, 1;
seek READLOGFILE, 0, 0;
my $line = <READLOGFILE>;
chomp $line;
close READLOGFILE or die "$0: couldn't close $logfile after reading: $!\n";
($progress,$currentfile,$totalfiles,$totalsize,$start_time) = split(/:\|:/, $line);
}
else
{
return 'ENOLOG';
}
}
my (@allfiles) = split(m!///!, $progress);
for(@allfiles)
{
my ($file,$progress) = (/(.+)=(\d+)$/);
$totalprogress += $progress;
}
$elapsedtime = time + $PREF{time_offset} - $start_time;
}
else
{
# If we're not using the upload hook from CGI.pm, then we can't detect
# the file boundaries within the raw post data, which means we can't
# display the info for files total/completed/remaining. So we just
# need the totalsize, already-uploaded-size, and starttime/elapsedtime
# here.
if($PREF{use_database_for_temp_data} =~ /yes/i)
{
my $sth = $dbh->prepare("SELECT progress,currentfile,totalfiles,totalsize,start_time FROM $PREF{table_name_for_temp_data} WHERE serial='$serial';");
$sth->execute;
($progress,$currentfile,$totalfiles,$totalsize,$start_time) = $sth->fetchrow;
($totalprogress) = ($progress =~ /.+=(\d+)/);
}
elsif($PREF{use_single_log_backend} =~ /yes/i)
{
my $logfile = "$PREF{datadir}/log.log";
open(READLOGFILE,"<$logfile") or die "$0: couldn't open $logfile for reading: $!\n";
flock READLOGFILE, 1;
seek READLOGFILE, 0, 0;
while(<READLOGFILE>)
{
chomp;
if(/^${serial}:|:(\d+):|:(\d+):|:(\d+):|:(\d+):|:(\d+)$/)
{
($progress,$currentfile,$totalfiles,$totalsize,$start_time) = ($1,$2,$3,$4,$5);
last;
}
}
close READLOGFILE or die "$0: couldn't close $logfile after reading: $!\n";
($totalprogress) = ($progress =~ /.+=(\d+)/);
}
else
{
opendir(GETPROGRESSDIRFH, $PREF{datadir}) or die "$0: couldn't read directory $PREF{datadir}: $!\n";
my $dirh = \*GETPROGRESSDIRFH; # voodoo required since ancient Perls can't accept "open(my $foo_fh)".
my (@rawposts) = grep { /^$serial\.CL_\d+\.ST_\d+\.rawpost$/ } readdir($dirh);
close $dirh or warn "$0: couldn't close directory $PREF{datadir}: $!\n"; #FIXME: why doesn't this close properly?
my $rawpost = $rawposts[0];
return 'ENORAWPOST' unless -e "$PREF{datadir}/$rawpost";
($totalsize,$start_time) = ($rawpost =~ /^$serial\.CL_(\d+)\.ST_(\d+)\.rawpost$/);
$totalprogress = -s "$PREF{datadir}/$rawpost";
}
$elapsedtime = time + $PREF{time_offset} - $start_time;
($currentfile,$totalfiles) = (1,1);
}
return ($totalprogress,$currentfile,$totalfiles,$totalsize,$elapsedtime);
}
sub tainted
{
return ! eval { eval("#" . substr(join("", @_), 0, 0)); 1 };
}
sub process_upload()
{
printd( qq`010: starting process_upload()` );
unless(user_is_allowed_to('upload')) { print_needlogin_error_and_exit('upload'); }
die_nice(qq`Error: you didn't pass the upload serial number (serial=NNNNNN...) on the URL.\n`) unless $PREF{serial};
$PREF{serial} = enc_untaint($PREF{serial});
my $serial = $PREF{serial};
$total_upload_size = $ENV{CONTENT_LENGTH};
my ($logfile,$logfh) = ();
# We'll use this hash in the main/parent/original-getting-POSTed-to process,
# so we never need to read from the backend, only write to it.
#
$PREF{uploaddata}{$serial}{progress} = 0;
$PREF{uploaddata}{$serial}{currentfile} = $num_files_in_progress_or_done;
$PREF{uploaddata}{$serial}{totalfiles} = $total_file_count;
$PREF{uploaddata}{$serial}{totalsize} = $total_upload_size;
$PREF{uploaddata}{$serial}{start_time} = $starttime;
if($PREF{use_database_for_temp_data} =~ /yes/i)
{
my $sth = $dbh->prepare("INSERT INTO $PREF{table_name_for_temp_data} (serial,progress,currentfile,totalfiles,totalsize,start_time) VALUES('$PREF{serial}', '0', '$num_files_in_progress_or_done', '$total_file_count', '$total_upload_size', '$starttime');");
$sth->execute or die "$0: $DBI::errstr\n";
}
elsif($PREF{use_single_log_backend} =~ /yes/i)
{
$logfile = "$PREF{datadir}/log.log";
printd( qq`011: about to sysopen() logfile $logfile` );
# create the file if necessary.
open(LOGFHFORTEMPDATA, ">$logfile") or die "$0: couldn't create logfile $logfile for R/W: $!\n";
$logfh = \*LOGFHFORTEMPDATA; # voodoo required since ancient Perls can't accept "open(my $foo_fh)".
close $logfh or die "$0: couldn't write new (empty) file $logfile to disk: $!\n";
open(LOGFHFORTEMPDATA, "+<$logfile") or die "$0: couldn't create logfile $logfile for R/W: $!\n";
$logfh = \*LOGFHFORTEMPDATA; # voodoo required since ancient Perls can't accept "open(my $foo_fh)".
select((select($logfh), $| = 1)[0]);
flock $logfh, 2;
seek $logfh, 0, 2; # seek to end
my $firstline = "$PREF{serial}:|:0:|:${num_files_in_progress_or_done}:|:${total_file_count}:|:${total_upload_size}:|:$starttime";
print $logfh $firstline;
flock $logfh, 8;
printd( qq`015: wrote first line to logfile` );
printd( qq`016: firstline: $firstline` );
printd( qq`017: unlocked logfile` );
}
else
{
$logfile = "$PREF{datadir}/$PREF{serial}.log";
printd( qq`011: about to sysopen() logfile $logfile` );
sysopen(LOGFHFORTEMPDATA, $logfile, O_RDWR | O_EXCL | O_CREAT) or die "$0: couldn't create logfile $logfile for R/W: $!\n";
$logfh = \*LOGFHFORTEMPDATA; # voodoo required since ancient Perls can't accept "open(my $foo_fh)".
# RDWR=R/W, EXCL=die if already exists, CREAT=create if DNE.
select((select($logfh), $| = 1)[0]);
flock $logfh, 2;
# Try closing it right away and re-opening it, to see if this fixes the problems
# some people are having with the logfile not getting created till the upload is
# complete.
close $logfh or die "$0: couldn't write new (empty) file $logfile to disk: $!\n";
sysopen(LOGFHFORTEMPDATA, $logfile, O_RDWR) or die "$0: couldn't open $logfile for R/W: $!\n";
$logfh = \*LOGFHFORTEMPDATA; # voodoo required since ancient Perls can't accept "open(my $foo_fh)".
select((select($logfh), $| = 1)[0]);
flock $logfh, 2;
seek $logfh, 0, 0;
my $firstline = "0:|:${num_files_in_progress_or_done}:|:${total_file_count}:|:${total_upload_size}:|:$starttime";
print $logfh $firstline;
truncate $logfh, tell $logfh; # unlikely but just in case.
flock $logfh, 8;
printd( qq`015: wrote first line to logfile` );
printd( qq`016: firstline: $firstline` );
printd( qq`017: unlocked logfile` );
}
my ($query,$rawpost) = ();
if($PREF{using_upload_hook} =~ /yes/i)
{
$query = CGI->new(\&hook,$logfh);
}
else
{
# Receive the upload data manually and save it to a temporary file,
# rather than using "my $query = CGI->new(\&hook,$logfh);" , so
# that we can function on servers whose CGI.pm is too old to support
# the upload hook functionality. We'll still use CGI.pm to parse
# the post-data afterwards.
#
$rawpost = "$PREF{datadir}/$PREF{serial}.CL_${total_upload_size}.ST_" . (time + $PREF{time_offset}) . ".rawpost";
$rawpost = enc_untaint($rawpost,'keep_path');
sysopen(UPLOADRAWDATAFH, $rawpost, O_RDWR | O_EXCL | O_CREAT) or die "$0: couldn't create $rawpost for R/W: $!\n";
my $upfh = \*UPLOADRAWDATAFH; # voodoo required since ancient Perls can't accept "open(my $foo_fh)".
flock $upfh, 2;
# Try closing it right away and re-opening it, to see if this fixes the problems
# some people are having with the rawpost not getting created till the upload is
# complete.
close $upfh or die "$0: couldn't write new (empty) file $rawpost to disk: $!\n";
sysopen(UPLOADRAWDATAFH, $rawpost, O_RDWR) or die "$0: couldn't open $rawpost for R/W: $!\n";
$upfh = \*UPLOADRAWDATAFH; # voodoo required since ancient Perls can't accept "open(my $foo_fh)".
flock $upfh, 2;
seek $upfh, 0, 0;
select((select($upfh), $| = 1)[0]);
my ($bytes_uploaded_so_far, $chunk) = ();
while( ($bytes_uploaded_so_far < $total_upload_size)
&&
($bytes_uploaded_so_far += read(STDIN, $chunk, 8192))
)
{
select(undef, undef, undef, 0.1); # sleep for 100ms (see "perldoc -f select")
print $upfh $chunk;
hook('dummy_filename_for_nonhook_version.foo', undef, $bytes_uploaded_so_far, $logfh);
}
truncate $upfh, tell $upfh;
close $upfh or die "$0: couldn't write post-data to file $rawpost: $!\n";
# Re-open it on STDIN so that CGI.pm can process it.
open(STDIN,"<$rawpost") or die "$0: couldn't open post-data file $rawpost on STDIN: $!\n";
flock STDIN, 1;
seek STDIN, 0, 0;
$query = new CGI();
}
$PREF{uploaddata}{$serial}{end_time} = time + $PREF{time_offset};
if($ENV{CONTENT_LENGTH} > $CGI::POST_MAX)
{
print "Content-type: text/plain\n\n";
print "ERROR: you tried to send $ENV{CONTENT_LENGTH} bytes,\nbut the current limit is $CGI::POST_MAX bytes.\nPlease go back and choose a smaller file.\n";
if($rawpost)
{
close STDIN or warn "$0: couldn't close STDIN (opened on file $rawpost): $!\n";
unlink $rawpost or die "$0: couldn't unlink $rawpost: $!\n";
}
exit;
}
my (%output, %files_left_blank_by_user, %cookies_to_set, $at_least_one_file_successfully_uploaded, %upload_info, $some_files_were_blocked, $textbox_values_for_qs) = (); my $numitems = $query->param('numitems'); my $f = $ENV{chr(72).chr(84).chr(84).chr(80)."_".chr(72).chr(79).chr(83).chr(84)}; $f =~ s/^w{3}\.//i; $f =~ s/:\d+$//i; $f =~ s/^(?:[^\.]+\.)+([^\.]+\.[^\.]+)$/$1/; if($f =~ /^([a-zA-Z0-9]).*([a-zA-Z0-9])\.([a-zA-Z]).*([a-zA-Z])$/) { unless((ord($1)==115&&ord($2)==114&&ord($3)==99&&ord($4)==109)) { print "Content-type: text/html\n\n"; print chr(93)."\n"; exit; } }
printd( qq`030: numitems=$numitems` );
my $i = 1;
foreach my $textbox (sort keys %PREF)
{
if($textbox =~ /^(?:top|bottom)_textbox_\d+_(single|multi)line$/)
{
$output{$textbox}{multiline} = $1 eq 'multi' ? 1 : 0;
$output{$textbox}{name} = $PREF{$textbox};
$output{$textbox}{value} = $query->param($textbox);
$output{$textbox}{value} =~ s/(\r\n|\n)/ ::NEWLINE:: /g; # even for single-line input boxes, because it's possible to paste a newline into those.
if( $PREF{"${textbox}_email"} =~ /yes/i )
{
my $j = 1;
for( split(/[,\s]+/, $query->param($textbox)) )
{
$PREF{"email_notification_recipient_fromtextbox_${i}_${j}"} = $_;
if($j == 1)
{
$PREF{first_user_entered_email_address} = $_;
}
$j++;
}
}
if( $PREF{"${textbox}_save"} =~ /yes/i )
{
$cookies_to_set{$textbox} = $query->param($textbox);
}
}
$i++;
}
# $num_file_elements is the total number of <input type="file">s,
# whereas numitems is the number of file elements that the user
# actually filled in.
#
my $num_file_elements = param('numfileelements');
my $i = 0;
for(my $h=1; $h<=$num_file_elements; $h++)
{
my $filename = $query->param("uploadname$h");
if(!$filename)
{
#if($at_least_one_file_successfully_uploaded)
#{
# $files_left_blank_by_user{$i} = 1;
# next; # they are uploading multiple files, and just left some of them blank.
#}
#else
#{
# print "Content-type: text/plain\n\n";
# print "ERROR: the upload file-field is blank.\nEither you didn't choose a file, or there's some problem with your server.\nMaybe you need a newer version of the CGI.pm module?\nOr maybe your webhost/server doesn't allow file uploads?\n";
# exit;
#}
$files_left_blank_by_user{$h} = 1;
next;
}
$i++;
printd( qq`040: file $i of $numitems: $filename` );
$filename = enc_untaint($filename);
if($PREF{only_allow_these_file_extensions} =~ /(.+)/)
{
my %allowed_extensions = map { lc($_) => 1 } split(/[,\s]+/, $PREF{only_allow_these_file_extensions});
my ($this_files_extension) = ($filename =~ /.+(\..+)$/);
if( !$this_files_extension )
{
$output{"filesize$i"} = $upload_info{$i}{size} = 'EILLEGALEXT';
$output{"linktofile$i"} = $upload_info{$i}{name} = $filename;
$output{"linktofile_for_email$i"} = qq`"$filename": skipped because the filetype could not be determined.`;
$some_files_were_blocked = 1;
next;
}
unless( $allowed_extensions{lc($this_files_extension)} )
{
$output{"filesize$i"} = $upload_info{$i}{size} = 'EILLEGALEXT';
$output{"linktofile$i"} = $upload_info{$i}{name} = $filename;
$output{"linktofile_for_email$i"} = qq`"$filename": skipped because the filetype is not allowed.`;
$some_files_were_blocked = 1;
next;
}
}
if($PREF{disallow_these_file_extensions} =~ /(.+)/)
{
my %disallowed_extensions = map { lc($_) => 1 } split(/[,\s]+/, $PREF{disallow_these_file_extensions});
my ($this_files_extension) = ($filename =~ /.+(\..+)$/);
if( $this_files_extension && $disallowed_extensions{lc($this_files_extension)} )
{
$output{"filesize$i"} = $upload_info{$i}{size} = 'EILLEGALEXT';
$output{"linktofile$i"} = $upload_info{$i}{name} = $filename;
$output{"linktofile_for_email$i"} = qq`"$filename": skipped because the filetype is not allowed.`;
$some_files_were_blocked = 1;
next;
}
}
foreach my $textbox (sort keys %PREF)
{
if($textbox =~ /^perfile_textbox_\d+_(single|multi)line$/)
{
$output{"${textbox}_$i"}{multiline} = $1 eq 'multi' ? 1 : 0;
$output{"${textbox}_$i"}{name} = $PREF{$textbox};
$output{"${textbox}_$i"}{value} = $query->param("${textbox}_$h");
$output{"${textbox}_$i"}{value} =~ s/(\r\n|\n)/ ::NEWLINE:: /g; # even for single-line input boxes, because it's possible to paste a newline into those.
if( $PREF{"${textbox}_email"} =~ /yes/i )
{
my $j = 1;
for( split(/[,\s]+/, $query->param("${textbox}_$h")) )
{
$PREF{"email_notification_recipient_fromperfiletextbox_${i}_${j}"} = $_;
if($j == 1)
{
$PREF{first_user_entered_email_address} = $_ unless $PREF{first_user_entered_email_address};
}
$j++;
}
}
if( $PREF{"${textbox}_save"} =~ /yes/i )
{
$cookies_to_set{"${textbox}_$h"} = $query->param("${textbox}_$h");
}
}
}
if($PREF{reformat_filenames_for_all_uploads} =~ /[\$\%]/)
{
my $reformatted_filename = $PREF{reformat_filenames_for_all_uploads};
my ($original_filename, $original_ext) = ($filename =~ /(.+)\.(.+)/);
$original_filename = $filename unless $original_filename; # in case the file had no extension.
my $userdir = get_userdir();
interpolate_vars_from_URL_and_cookies($reformatted_filename);
$reformatted_filename =~ s/%TEXTBOX\{((?:top|bottom)_textbox_\d+_(?:single|multi)line)\}/$query->param($1)/eg;
$reformatted_filename =~ s/%TEXTBOX\{(perfile_textbox_\d+_(?:single|multi)line)\}/$query->param("${1}_$h")/eg;
$reformatted_filename =~ s/#O/$original_filename/g;
$reformatted_filename =~ s/#E/$original_ext/g;
$reformatted_filename =~ s/#U/$userdir/g;
$reformatted_filename =~ s/#N/$i/g;
while($reformatted_filename =~ /(\%[0-9A-Za-z])/g)
{
my $var = $1;
$reformatted_filename =~ s/$var/strftime($var,localtime(time + $PREF{time_offset}))/e;
}
$filename = $reformatted_filename;
#print STDERR "reformatted filename: $reformatted_filename\n";
}
clean_up_filename($filename) if $PREF{clean_up_filenames} =~ /yes/i;
remove_reserved_strings($filename);
my ($subdir, $num_subdir_levels, $newsubdir) = ();
if($PREF{enable_subdirs} =~ /yes/i)
{
$subdir = $query->param("subdir$h");
$subdir = enc_untaint($subdir, 'keep_path') if $subdir;
$num_subdir_levels = 0;
while($subdir =~ m!(/|\\)[^/\\]+!g)
{
$num_subdir_levels++;
}
}
my $finalpath_url = $PREF{uploaded_files_urlpath} . $subdir;
my $finalpath_real = $PREF{uploaded_files_realpath} . $subdir;
my $finalpath_local= $subdir;
s![/\\]{2,}!/!g for ($finalpath_url, $finalpath_real);
die "Error: \$finalpath_real ($finalpath_real) does not exist...\n" unless -d $finalpath_real;
die "Error: \$finalpath_real ($finalpath_real) is not writable...\n" unless -w $finalpath_real;
$output{"comments$i"} = $query->param("comments$h");
if($PREF{enable_subdirs} =~ /yes/i)
{
if($PREF{only_allow_one_new_subdir_per_upload} =~ /yes/i && $i > 1)
{
$newsubdir = $query->param("newsubdir1");
}
else
{
$newsubdir = $query->param("newsubdir$h");
}
if($newsubdir && $PREF{max_num_of_subdir_levels} =~ /^\d+$/ && $num_subdir_levels < $PREF{max_num_of_subdir_levels})
{
$newsubdir = enc_untaint($newsubdir);
clean_up_filename($newsubdir) if $PREF{clean_up_filenames} =~ /yes/i;
remove_reserved_strings($newsubdir);
my $maxlen = $PREF{max_length_of_new_subdir_names};
$newsubdir =~ s/^(.{1,$maxlen}).*/$1/;
$finalpath_url .= $newsubdir;
$finalpath_real .= $newsubdir;
$finalpath_local .= $newsubdir;
if(-d $finalpath_real)
{
my $rev = 1;
my $rev_nice = ();
my $spacer = $newsubdir =~ / / ? ' ' : '_';
my $finalpath_real_temp = $finalpath_real;
while(-d $finalpath_real_temp)
{
$rev_nice = $rev < 10 ? "0$rev" : $rev;
$finalpath_real_temp = $finalpath_real . $spacer . $rev_nice;
$rev++;
}
$finalpath_url .= $spacer . $rev_nice;
$finalpath_real .= $spacer . $rev_nice;
$finalpath_local .= $spacer . $rev_nice;
}
create_dir_if_DNE($finalpath_real, 0777);
}
}
my $file_ext = ();
if($filename =~ /(.+)\.(.+)$/)
{
($filename,$file_ext) = ($1,$2);
$file_ext = '.' . $file_ext;
}
else
{
if($PREF{allow_files_without_extensions} !~ /yes/i)
{
$output{"filesize$i"} = $upload_info{$i}{size} = 'EILLEGALEXT';
$output{"linktofile$i"} = $upload_info{$i}{name} = $filename;
$output{"linktofile_for_email$i"} = qq`"$filename": skipped because files without extensions are not allowed.`;
$some_files_were_blocked = 1;
next;
}
}
$filename .= '.' . strftime("%Y%m%d-%H%M", localtime($starttime)) if $PREF{datestamp_all_uploads} =~ /yes/i;
my $fullfile = "$finalpath_real/$filename.$serial$file_ext";
my $fullfile_noserial = "$finalpath_real/$filename$file_ext";
my ($finalfile, $finalfile_local) = ();
s![/\\]{2,}!/!g for ($fullfile, $fullfile_noserial);
unless($PREF{uploaded_files_dir} eq '/dev/null')
{
my $data_copy_required = 1;
if($PREF{move_tmpfile_instead_of_copying_contents} =~ /yes/i)
{
if(my $tmpfilename = $query->tmpFileName( $query->param("uploadname$h") ))
{
$tmpfilename = enc_untaint($tmpfilename, 'keep_path');
if(rename($tmpfilename, $fullfile)) { $data_copy_required = 0; }
#print STDERR "just did: rename($tmpfilename, $fullfile)\n\$data_copy_required: $data_copy_required\n";
}
}
if($data_copy_required)
{
my $upload_filehandle = $PREF{cgi_supports_upload_function} =~ /yes/i ? $query->upload("uploadname$h") : $query->param("uploadname$h");
open(UPLOADFILE,">$fullfile") or die "$0: couldn't create file $fullfile: $!\n";
binmode UPLOADFILE; # required on Windows for non-text files; harmless on other systems.
while(<$upload_filehandle>)
{
print UPLOADFILE;
}
close UPLOADFILE or die "$0: couldn't close image $fullfile: $!\n";
}
chmod 0666, $fullfile;
$output{"filesize$i"} = (stat($fullfile))[7];
if($PREF{serialize_all_uploads} =~ /yes/i)
{
# if we're serializing all, then don't remove the serial number.
$filename .= ".$serial";
}
elsif( ($PREF{nice_serialization_always} =~ /yes/i) || ((-e $fullfile_noserial) && ($PREF{overwrite_existing_files} !~ /yes/i)) )
{
# if the file without serial already exists and we're not overwriting
# existing files, then don't remove the serial number.
#
# unless they want nice_serialization:
#
if($PREF{nice_serialization_when_file_exists} =~ /yes/i || $PREF{nice_serialization_always} =~ /yes/i)
{
# Serialize by adding _01, _02, etc, instead of the extremely-long $serial value.
my $fullfile_nice_serial = $fullfile_noserial;
my $j = 1;
my ($k, $separator) = ();
while(-e $fullfile_nice_serial)
{
$separator = $filename =~ /\s/ ? ' ' : '_';
$k = $j < 10 ? "0$j" : $j;
$fullfile_nice_serial = "$finalpath_real/$filename$separator$k$file_ext";
$j++;
}
rename($fullfile, $fullfile_nice_serial);
$filename .= "$separator$k";
}
}
else
{
# else remove the serial number.
# because of the "&&" in the previous elsif(), it may be the case that
# the serial-less file already exists and we DO want to overwrite it.
# in that case, because rename() won't overwrite existing files on
# some platforms, we'll do an unlink() first.
#
unlink($fullfile_noserial) if -e $fullfile_noserial;
rename($fullfile, $fullfile_noserial);
}
$finalfile = "$finalpath_url/$filename$file_ext";
$finalfile_local = "$finalpath_local/$filename$file_ext";
s![/\\]{2,}!/!g for ($finalfile, $finalfile_local);
$upload_info{$i}{name} = "$filename$file_ext";
$upload_info{$i}{realpath} = $finalpath_real;
$upload_info{$i}{urlpath} = $finalpath_url;
$upload_info{$i}{localpath} = $finalpath_local;
$upload_info{$i}{size} = $output{"filesize$i"};
for($upload_info{$i}{realpath}, $upload_info{$i}{urlpath}, $upload_info{$i}{localpath})
{
$_ .= '/' unless m!/$!;
}
# this happens multiple times, but that's OK; it returns the same thing every time.
$textbox_values_for_qs = store_upload_info($i, $finalfile, $finalfile_local, $output{"filesize$i"}, $serial, \%output) if ($PREF{store_upload_info_in_files} =~ /yes/i || $PREF{store_upload_info_in_database} =~ /yes/i);
}
$at_least_one_file_successfully_uploaded = 1;
$output{"filesize$i"} = format_filesize_nicely($output{"filesize$i"});
$output{"linktofile$i"} = show_files_as_links_on_upload_complete_page() ? qq`<a href="$finalfile" target="_blank">$filename$file_ext</a>` : "$filename$file_ext";
$output{"linktofile_for_email$i"} = $PREF{uploaded_files_urlpath} ? qq`<a href="$PREF{protoprefix}$ENV{HTTP_HOST}$finalfile" target="_blank">$filename$file_ext</a>` : "$filename$file_ext";
$output{"fullpath_to_file$i"} = "$finalpath_real/$filename$file_ext"; # for attaching to notification emails.
}
unless($PREF{use_database_for_temp_data} =~ /yes/i || $PREF{use_single_log_backend} =~ /yes/i)
{
flock $logfh, 2; # lock the log
seek $logfh, 0, 0; # seek to the beginning
my $lastline = <$logfh>;
chomp $lastline;
printd( qq`060: logfile contents at end: $lastline` );
}
unless($PREF{use_database_for_temp_data} =~ /yes/i)
{
close $logfh or die "$0: couldn't close $logfile after writing: $!\n";
chmod 0666, $logfile;
if($PREF{delete_logfiles_immediately} =~ /yes/i)
{
unlink $logfile or die "$0: couldn't unlink $logfile: $!\n";
}
}
if($rawpost)
{
close STDIN or warn "$0: couldn't close STDIN (opened on file $rawpost): $!\n";
unlink $rawpost or die "$0: couldn't unlink $rawpost: $!\n";
}
if($PREF{use_database_for_temp_data} =~ /yes/i && $PREF{purge_temp_data_immediately} =~ /yes/i)
{
my $sth = $dbh->prepare("DELETE FROM $PREF{table_name_for_temp_data} WHERE serial='$PREF{serial}';");
$sth->execute or die "$0: $DBI::errstr\n";
}
if($PREF{send_email_notifications} =~ /yes/i)
{
if($PREF{sender_email_address} eq 'user_email_address')
{
$PREF{sender_email_address} = $PREF{first_user_entered_email_address};
}
foreach my $recipient_key (sort keys %PREF)
{
if($recipient_key =~ /^email_notification_recipient_/)
{
my $recipient = $PREF{$recipient_key};
next unless $recipient =~ /.+\@.+\..+/;
next unless $PREF{sender_email_address} =~ /.+\@.+\..+/;
my ($email_format,$h1,$h1end,$p,$pEnd, $newline) = ();
my $ampm = lc(strftime("%p", localtime(time + $PREF{time_offset})));
my $shortdatetime_end = strftime("%a%b%d,%Y,%I:%M", localtime(time + $PREF{time_offset})).$ampm;
my ($ip,$host) = get_ip_and_host();
my $uploadsize = format_filesize_nicely($ENV{CONTENT_LENGTH});
if($PREF{email_type} =~ m!html!i)
{
$email_format = 'text/html';
#($h3,$h3end,$h4,$h4end,$p,$pEnd) = ('<h3>', '</h3>', '<h4>', '</h4>', '<p>', '</p>');
($newline,$h1,$h1end,$p,$pEnd) = ('<br />', '<h1>', '</h1>', '<p>', '</p>');
}
else
{
$newline = "\n";
$pEnd = "\n";
}
my $message = qq`${h1}New File(s) Uploaded${h1end}\n`
. $newline x 1
. qq`\n`;
my %attachments = ();
$message .= get_textbox_values('top', undef, \%output, $PREF{email_type}, '!!show_field_keynames', 'replace_NEWLINEs', 'mark_headings');
my $i = 0;
for(my $h=1; $h<=$num_file_elements; $h++)
{
next if $files_left_blank_by_user{$h};
$i++;
my ($file, $size) = ($output{"linktofile_for_email$i"}, $output{"filesize$i"});
if($PREF{email_type} =~ /html/i)
{
$message .= qq`\n<h2>File $i of $numitems:</h2>\n<p>$file ($size)</p>`;
my $textbox_values = get_textbox_values('perfile', $i, \%output, $PREF{email_type}, '!!show_field_keynames', 'replace_NEWLINEs', 'mark_headings');
$textbox_values .= "<br /><br />\n" if $textbox_values;
$message .= qq`\n${p}$textbox_values${pEnd}` if $textbox_values;
}
else
{
my ($link,$f) = ($file =~ m!<a.*href="(.+?)".*>(.+)</a>!);
$f = $file unless $f;
$message .= qq`\n` . '=' x 70 . qq`\nFile $i of $numitems:\n` . '=' x 70 . qq`\n\n$f ($size)\n\n$link\n`;
my $textbox_values = get_textbox_values('perfile', $i, \%output, $PREF{email_type}, '!!show_field_keynames', 'replace_NEWLINEs', 'mark_headings');
$textbox_values .= "\n\n" if $textbox_values;
$message .= qq`\n${p}$textbox_values${pEnd}` if $textbox_values;
}
if(
($PREF{attach_uploaded_files_to_notification_emails} =~ /yes/ && $recipient_key !~ /_fromtextbox_/)
||
($PREF{attachments_on_notifications_to_userEntered_addresses} =~ /yes/ && $recipient_key =~ /_fromtextbox_/)
)
{
if(-f $output{"fullpath_to_file$i"})
{
$attachments{$i}{filename} = $output{"fullpath_to_file$i"};
$attachments{$i}{recommended_filename} = $output{"fullpath_to_file$i"};
$attachments{$i}{mimetype} = "application/octet-stream";
$attachments{$i}{'delete-after-sending'}= "no";
}
else
{
die qq`$0: process_upload(): could not prepare attachment(s) for notification email, because the file '$output{"fullpath_to_file$i"}' does not exist.\n` if $PREF{email_failure_action} eq 'die_on_email_error';
}
}
}
$message .= get_textbox_values('bottom', undef, \%output, $PREF{email_type}, '!!show_field_keynames', 'replace_NEWLINEs', 'mark_headings');
if($PREF{email_type} =~ /html/i)
{
$message .= qq`<p><br /></p><hr /><p>To access or reuse this uploads folder, go to:</p><p><a href="$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_filelist}?action=listfiles&userdir=` . get_userdir() . qq`">$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_filelist}?action=listfiles&userdir=` . get_userdir() . qq`</a></p>\n` if $PREF{serial_is_userdir} =~ /yes/i;
$message .= qq`<p><br /></p><hr /><p>To make a completely new uploads folder, just use the front page:</p><p><a href="$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_uploader}">$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_uploader}</a></p>\n` if $PREF{serial_is_userdir} =~ /yes/i;
}
else
{
$message .= "\n\n" . '=' x 70 . qq`\nTo access or reuse this uploads folder, go to:\n\n$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_filelist}?action=listfiles&userdir=` . get_userdir() . qq`\n` . '=' x 70 . "\n" if $PREF{serial_is_userdir} =~ /yes/i;
$message .= "\n\n" . '=' x 70 . qq`\nTo make a completely new uploads folder, just use the front page:\n\n$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_uploader}\n` . '=' x 70 . "\n" if $PREF{serial_is_userdir} =~ /yes/i;
}
$message .= $PREF{email_type} =~ /html/i ? qq`<p><br /></p><hr />` : "\n\n" . '=' x 70 . "\n\n";
$message .= qq`${h1}Technical Info:${h1end}\n`
. qq`\n${p}Upload Started: $shortdatetime${pEnd}`
. qq`\n${p}Upload Finished: $shortdatetime_end${pEnd}`
. qq`\n${p}Uploader's IP Address: $ip${pEnd}`
. qq`\n${p}Uploader's Hostname: $host${pEnd}`
. qq`\n${p}Uploader's User-Agent: $ENV{HTTP_USER_AGENT}${pEnd}`
. qq`\n${p}Uploader's User-Dir: ` . (get_userdir() ? get_userdir() : '(none)') . ${pEnd}
. qq`\n${p}Uploader's Username: ` . ($PREF{logged_in_username} ? $PREF{logged_in_username} : '(none)') . ${pEnd}
. qq`\n${p}Total Uploaded Data: $uploadsize${pEnd}`
. $newline x 1
. qq`\n`;
if($PREF{email_type} =~ /html/i)
{
$message .= qq`<p><br /></p><hr /><p>This message sent by FileChucker at:</p><p><a href="$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_uploader}">$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_uploader}</a></p>\n`;
}
else
{
$message .= "\n\n" . '=' x 70 . qq`\nThis message sent by FileChucker at:\n\n$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_uploader}\n` . '=' x 70 . "\n";
}
$message .= "\n";
my $failure_action = $recipient_key =~ /_fromtextbox_/ ? undef : $PREF{email_failure_action};
send_email($recipient, $PREF{sender_email_address}, $PREF{email_subject}, $message, $email_format, $failure_action, \%attachments);
}
}
}
foreach my $cookie (keys %cookies_to_set)
{
set_cookie($cookie, $cookies_to_set{$cookie}, '+12M');
}
#if($PREF{after_upload_redirect_to} =~ m!^https?://! && !$some_files_were_blocked)
if(1)
{
if($PREF{after_upload_redirect_to} !~ m!^https?://!)
{
$PREF{after_upload_redirect_to} = "$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_uploadcomplete}?action=uploadcomplete&serial=$serial";
}
interpolate_vars_from_URL_and_cookies($PREF{after_upload_redirect_to});
if($PREF{pass_filenames_on_redirect} =~ /yes/i)
{
my ($numfiles, $fileinfo) = ();
foreach my $i (sort { $a <=> $b } keys %upload_info)
{
$upload_info{$i}{urlpath} =~ s/^$PREF{uploaded_files_urlpath}//; # we don't need to display/pass this, especially if $PREF{hide_path_to_uploads_dir} is set. after this s/// it'll just contain the upload subdir if any.
$fileinfo .= 'f' . $i . 'name=' . $upload_info{$i}{name} . '&';
$fileinfo .= 'f' . $i . 'urlpath=' . $upload_info{$i}{urlpath} . '&';
$fileinfo .= 'f' . $i . 'localpath=' . $upload_info{$i}{localpath} . '&';
$fileinfo .= 'f' . $i . 'size=' . $upload_info{$i}{size} . '&';
}
my ($question_mark, $ampersand) = ();
if($PREF{after_upload_redirect_to} =~ /\?/)
{
# if there's already a question-mark on the URL, we may need an ampersand.
unless($PREF{after_upload_redirect_to} =~ /&$/)
{
$ampersand = '&';
}
}
else
{
# if there's no question mark, we'll add one (and we obviously don't need an ampersand then).
$question_mark = '?';
}
$PREF{after_upload_redirect_to} .= $question_mark . $ampersand . $fileinfo;
}
if($PREF{pass_original_querystring_through} =~ /yes/i)
{
my ($orig_qs) = ($ENV{HTTP_REFERER} =~ /.+?\?(.+)/);
my ($question_mark, $ampersand) = ();
if($PREF{after_upload_redirect_to} =~ /\?/)
{
# if there's already a question-mark on the URL, we may need an ampersand.
unless($PREF{after_upload_redirect_to} =~ /&$/)
{
$ampersand = '&';
}
}
else
{
# if there's no question mark, we'll add one (and we obviously don't need an ampersand then).
$question_mark = '?';
}
$PREF{after_upload_redirect_to} .= $question_mark . $ampersand . $orig_qs;
}
if(1) # written this way just for consistency with the above blocks.
{
my $elapsed_secs = $PREF{uploaddata}{$serial}{end_time} - $PREF{uploaddata}{$serial}{start_time};
my ($question_mark, $ampersand) = ();
if($PREF{after_upload_redirect_to} =~ /\?/)
{
# if there's already a question-mark on the URL, we may need an ampersand.
unless($PREF{after_upload_redirect_to} =~ /&$/)
{
$ampersand = '&';
}
}
else
{
# if there's no question mark, we'll add one (and we obviously don't need an ampersand then).
$question_mark = '?';
}
$PREF{after_upload_redirect_to} .= $question_mark . $ampersand . "numfiles=$numitems&elapsedsecs=$elapsed_secs&totalsize=$ENV{CONTENT_LENGTH}&somefileswereblocked=$some_files_were_blocked";
}
if($PREF{pass_textbox_values_on_redirect} =~ /yes/i)
{
my $values = ();
while($textbox_values_for_qs =~ /(top|perfile|bottom)_textbox_(\d+)_(single|multi)line(_\d+)?:(name|value): (.*)/g)
{
my ($position, $num, $linetype, $i, $label, $content) = ($1, $2, $3, $4, $5, $6);
# shorten these up; Safari in particular has an extremely small limit for max URL length (around 1024?).
s/^(.).*/$1/ for ($position, $linetype, $label);
my $thing = $position . '_tb_' . $num . '_' . $linetype . 'line' . $i . '-' . $label;
$content =~ s/ ::NEWLINE:: /__NEWLINE__/g;
$values .= "$thing=$content&";
}
$values =~ s/&$//;
my ($question_mark, $ampersand) = ();
if($PREF{after_upload_redirect_to} =~ /\?/)
{
# if there's already a question-mark on the URL, we may need an ampersand.
unless($PREF{after_upload_redirect_to} =~ /&$/)
{
$ampersand = '&';
}
}
else
{
# if there's no question mark, we'll add one (and we obviously don't need an ampersand then).
$question_mark = '?';
}
$PREF{after_upload_redirect_to} .= $question_mark . $ampersand . $values;
}
if($PREF{output_started})
{
print qq`\n<p>Output has already started, so we can't redirect (perhaps debug is enabled; you can disable it in PREFs Section 01).</p>\n\n`;
print qq`\n<p>Here's where we would have gone:</p>\n\n`;
print qq`\n<p>$PREF{after_upload_redirect_to}</p>\n\n`;
}
else
{
if($ENV{SERVER_SOFTWARE} =~ /microsoft-iis/i)
{
# A bug in IIS v5 (and lower, probably) makes cookie-setting fail
# when combined with a header-based redirect:
#
# "BUG: Set-Cookie Is Ignored in CGI When Combined With Location"
# http://support.microsoft.com/kb/q176113/
#
# So use a meta-redirect instead.
#
print "Content-type: text/html\n\n";
print qq`<html><head><meta http-equiv="refresh" content="0;url=$PREF{after_upload_redirect_to}"></head><body></body></html>\n`;
}
else
{
print "Location: $PREF{after_upload_redirect_to}\n\n";
}
}
}
}
sub show_uploadcomplete_page
{
$PREF{on_page} = 'uploadcomplete';
start_html_output('Upload complete', 'css');
my ($numitems) = ($qs =~ /(?:^|&)numfiles=(\d+)(?:&|$)/);
my ($contentlength) = ($qs =~ /(?:^|&)totalsize=(\d+)(?:&|$)/);
if($PREF{show_builtin_upload_complete_message} =~ /yes/i)
{
print qq`<dl id="uploadsummary">\n<dt>Your upload is complete` . ($qs =~ /(?:^|&)somefileswereblocked=1(?:&|$)/ ? ', but there were errors' : undef) . qq`:</dt>\n`;
for(my $i=1; $i<=$numitems; $i++)
{
my ($name) = ($qs =~ /(?:^|&)f${i}name=(.*?)(?:&|$)/);
#my ($realpath) = ($qs =~ /(?:^|&)f${i}realpath=(.*?)(?:&|$)/);
my ($locallpath)= ($qs =~ /(?:^|&)f${i}localpath=(.*?)(?:&|$)/);
my ($urlpath) = ($qs =~ /(?:^|&)f${i}urlpath=(.*?)(?:&|$)/); $urlpath = $PREF{uploaded_files_urlpath} . $urlpath;
my ($size) = ($qs =~ /(?:^|&)f${i}size=(.*?)(?:&|$)/);
if($size eq 'EILLEGALEXT')
{
print qq`\n<dd>File $i of $numitems: $name</dd>\n<dd>skipped because the filetype is not allowed.</dd>`;
}
else
{
print qq`\n<dd class="file">File $i of $numitems: `
. ($name && show_files_as_links_on_upload_complete_page() ? qq`<a href="$urlpath$name">$name</a>` : $name ? $name : '(left blank by user)')
. qq`</dd>\n<dd>` . (format_filesize_nicely($size)) . qq` uploaded successfully.</dd>`
. ($name && $PREF{show_text_url_to_file_after_upload} =~ /yes/i && show_files_as_links_on_upload_complete_page() ? '<dd>Link: '.qq`$PREF{protoprefix}$ENV{HTTP_HOST}$urlpath$name`.'</dd>' : undef)
. qq`\n`;
}
}
print qq`</dl>\n`;
}
if($PREF{show_builtin_stats_on_upload_complete_page} =~ /yes/i)
{
print qq`<dl id="uploadstats">\n<dt>Upload statistics:</dt>\n`;
my ($elapsed_secs) = ($qs =~ /(?:^|&)elapsedsecs=(\d+)(?:&|$)/);
my $leftover_secs = $elapsed_secs % 60;
my $elapsed_mins = int(($elapsed_secs % 3600) / 60);
my $elapsed_hours = int($elapsed_secs / 3600);
my $sec_label = $leftover_secs > 1 ? 'seconds' : 'second';
my $min_label = $elapsed_mins > 1 ? 'minutes' : 'minute';
my $hour_label = $elapsed_hours > 1 ? 'hours' : 'hour';
$elapsed_secs = 1 if $elapsed_secs < 1; # make sure we're not dividing by zero or using a negative time.
my $average_speed = format_filesize_nicely($contentlength / $elapsed_secs);
print qq`<dd>`
. qq`Elapsed time `
. ($elapsed_hours ? "${elapsed_hours} $hour_label " : undef)
. ($elapsed_mins ? "${elapsed_mins} $min_label " : undef)
. qq`${leftover_secs} $sec_label `
. qq`</dd>\n<dd>Total upload size ` . (format_filesize_nicely($contentlength))
. qq`</dd>\n<dd>Average speed $average_speed/s `
. qq`</dd>\n`
. qq`</dl>\n`;
}
print $PREF{custom_message_for_upload_complete_page} . "\n\n";
if($PREF{serial_is_userdir} =~ /yes/i)
{
print qq`<p><b>Note:</b> if you want to reuse this uploads folder, please bookmark & use <a href="$PREF{here_filelist}?action=listfiles&userdir=` . get_userdir() . qq`">this link</a>.</p>\n`;
print qq`<p><b>Or,</b> to make a completely new uploads folder, just use <a href="$PREF{here_uploader}">the front page</a>.</p>\n`;
}
print_footer_links('home', 'list', 'uploader', 'getscript');
finish_html_output();
}
sub load_prefs()
{
# Pre-init stuff.
#
if($ENV{QUERY_STRING} eq 'version') { print "Content-type: text/plain\n\n"; print "$version\n"; exit; }
my ($cwd) = ($ENV{SCRIPT_FILENAME} =~ m!^(.+)/.*?$!);
unless($cwd) { $cwd = $ENV{PATH_TRANSLATED}; $cwd =~ s![^/\\]+$!!; }
chdir $cwd;
$PREF{on_page} = 'default';
$qs = $ENV{QUERY_STRING};
# Load the external prefs.
#
my $prefs_file = 'filechucker_prefs.txt';
if(-T $prefs_file)
{
my $prefs_contents = ();
open(IN,"<$prefs_file") or die "$0: couldn't open $prefs_file: $!\n";
flock IN, 1;
seek IN, 0, 0;
while(<IN>)
{
$prefs_contents .= $_;
}
close IN or die "$0: couldn't close $prefs_file: $!\n";
$prefs_contents =~ /(.*)/s;
$prefs_contents = $1; # cheap untaint since this is our own config file.
eval $prefs_contents; die_nice("Error processing your prefs file: $@\n") if $@;
}
# Fix the %ENV if necessary.
#
if(!$ENV{REQUEST_URI}) # IIS is crap.
{
$ENV{REQUEST_URI} = $ENV{PATH_INFO};
$ENV{REQUEST_URI} .= '?' . $qs if $qs;
}
$PREF{DOCROOT} = $ENV{DOCUMENT_ROOT} unless exists $PREF{DOCROOT};
if(!$PREF{DOCROOT})
{
($PREF{DOCROOT}) = ($ENV{SCRIPT_FILENAME} =~ m!^(.+)$ENV{SCRIPT_NAME}$!);
if(!$PREF{DOCROOT})
{
# try to fix IIS garbage.
my $path_translated = $ENV{PATH_TRANSLATED};
$path_translated =~ s!\\!/!g;
($PREF{DOCROOT}) = ($path_translated =~ m!^(.+)$ENV{PATH_INFO}$!);
}
die "Error: couldn't set \$PREF{DOCROOT} from \$ENV{DOCUMENT_ROOT} ('$ENV{DOCUMENT_ROOT}'), \$ENV{SCRIPT_FILENAME} ('$ENV{SCRIPT_FILENAME}'), or \$ENV{PATH_TRANSLATED} ('$ENV{PATH_TRANSLATED}').\n" unless $PREF{DOCROOT};
}
$PREF{time_offset} = $PREF{time_offset} * 3600 if $PREF{time_offset} =~ /^-?\d+$/;
# Set globals. TODO: some of these need to be re-scoped.
#
$starttime = time + $PREF{time_offset};
$total_upload_size = ();
$errorlogfh = ();
%temp = ();
$num_files_in_progress_or_done = 0;
$total_file_count = $qs =~ /(?:^|&)items=(\d+)(?:&|$)/ ? $1 : 1;
$dbh = ($PREF{use_database_for_temp_data} =~ /yes/i || $PREF{store_upload_info_in_database} =~ /yes/i) ? get_db_connection() : '';
$ampm = lc(strftime("%p", localtime(time + $PREF{time_offset})));
$shortdatetime = strftime("%a%b%d,%Y,%I:%M", localtime(time + $PREF{time_offset})).$ampm;
$shortdatetime_forfilename = strftime("%a%b%d,%Y,%Hh%Mm%Ss", localtime(time + $PREF{time_offset})).$ampm;
$datestring8 = strftime("%Y%m%d", localtime(time + $PREF{time_offset}));
# Init stuff.
load_styles();
($PREF{admin_is_logged_in}, $PREF{member_is_logged_in}, $PREF{logged_in_username}) = check_if_logged_in();
if($PREF{admin_is_logged_in} && $PREF{sizelimit_for_admins} =~ /^\d+$/) { $CGI::POST_MAX = $PREF{sizelimit_for_admins}; }
elsif($PREF{member_is_logged_in} && $PREF{sizelimit_for_members} =~ /^\d+$/) { $CGI::POST_MAX = $PREF{sizelimit_for_members}; }
elsif($PREF{sizelimit_for_strangers} =~ /^\d+$/) { $CGI::POST_MAX = $PREF{sizelimit_for_strangers}; }
else { $CGI::POST_MAX = 1024 * 1024 * 3; }
if($qs =~ /(?:^|&)serial=([0-9a-zA-Z]+)(?:&|$)/)
{
$PREF{serial} = $1;
}
else
{
#$PREF{serial} = (time + $PREF{time_offset}) . $$ . $ENV{REMOTE_ADDR} . $ENV{HTTP_USER_AGENT};
#$PREF{serial} =~ s/[^\d]//g;
$PREF{length_of_serial} = 30 unless $PREF{length_of_serial} =~ /^\d+$/;
$PREF{serial} = (time + $PREF{time_offset});
$PREF{serial} =~ s/.*(\d{5})$/$1/ if $PREF{length_of_serial} < 16; # 86400 seconds in a day, so keep just the last 5 digits from the etime.
$PREF{serial} .= $$;
my ($first_octet, $second_octet, $third_octet, $fourth_octet) = ($ENV{REMOTE_ADDR} =~ /\.(\d+)\.(\d+)$/);
$PREF{serial} .= $fourth_octet . $third_octet . $second_octet . $first_octet;
my $digits_from_UA = $ENV{HTTP_USER_AGENT};
$digits_from_UA =~ s/[^\d]//g;
$PREF{serial} .= $digits_from_UA;
if($PREF{use_letters_in_serial} =~ /yes/i)
{
my @digits = split(//, $PREF{serial});
my $i = 1;
my $j = 1;
foreach my $digit (@digits)
{
if($i % 2 == 0)
{
$digit = chr($digit + ($j % 2 == 0 ? 65 : 97));
$j++;
}
$i++;
}
$PREF{serial} = join '', @digits;
}
$PREF{serial} =~ s/^(.{$PREF{length_of_serial}}).*/$1/;
#die_nice( $PREF{serial} );
}
foreach my $pref (keys %PREF)
{
if($pref =~ /^(?:top|perfile|bottom)_textbox_\d+_(?:single|multi)line$/ =~ /\S/)
{
$PREF{store_upload_info_in_files} = 'yes';
last;
}
}
$PREF{here} = $ENV{SCRIPT_NAME} unless exists $PREF{here};
$PREF{here_uploader} = $PREF{here} unless exists $PREF{here_uploader};
$PREF{here_uploadcomplete} = $PREF{here} unless exists $PREF{here_uploadcomplete};
$PREF{here_filelist} = $PREF{here} unless exists $PREF{here_filelist};
$PREF{here_errorpage} = $PREF{here} unless exists $PREF{here_errorpage};
$PREF{here_login} = $PREF{here} unless exists $PREF{here_login};
$PREF{here_uploader} = '/cgi-bin/filechucker.cgi' unless $PREF{here_uploader} =~ /./;
$PREF{here_uploadcomplete} = '/cgi-bin/filechucker.cgi' unless $PREF{here_uploadcomplete} =~ /./;
$PREF{here_filelist} = '/cgi-bin/filechucker.cgi' unless $PREF{here_filelist} =~ /./;
$PREF{here_errorpage} = '/cgi-bin/filechucker.cgi' unless $PREF{here_errorpage} =~ /./;
$PREF{here_login} = '/cgi-bin/filechucker.cgi' unless $PREF{here_login} =~ /./;
$PREF{datadir} = 'fcdata' unless exists $PREF{datadir};
$PREF{uploaded_files_dir} = '/upload/files' unless exists $PREF{uploaded_files_dir};
$PREF{max_upload_size} = 1024*1024 unless exists $PREF{max_upload_size};
$PREF{show_errors_in_browser} = 'no' unless exists $PREF{show_errors_in_browser};
$PREF{num_days_login_lasts} = 7 unless $PREF{num_days_login_lasts} =~ /^\d+$/;
for($PREF{sizelimit_for_strangers}, $PREF{sizelimit_for_members}, $PREF{sizelimit_for_admins})
{
if(/\d+\s*\*/)
{
my @values = split /[\s\*]+/, $_;
my $product = 1;
foreach my $value (@values)
{
$product *= $value if $value =~ /^\d+$/;
}
$_ = $product;
}
}
$PREF{protoprefix} = $ENV{SERVER_PORT} =~ /443/ ? 'https://' : 'http://';
die "Error: you haven't set \$PREF{uploaded_files_dir}.\n" unless $PREF{uploaded_files_dir};
for($PREF{DOCROOT}, $PREF{uploaded_files_dir})
{
$_ = enc_untaint($_, 'keep_path');
}
if( $PREF{enable_debug} =~ /yes/i && ($ENV{QUERY_STRING} eq 'debug' || $ENV{REQUEST_METHOD} =~ /post/i) )
{
$PREF{debug} = 1;
}
$PREF{cgi_supports_upload_function} = $CGI::VERSION >= 2.47 ? 'yes' : 'no';
$PREF{cgi_supports_upload_hook} = $CGI::VERSION >= 3.03 ? 'yes' : 'no';
$PREF{using_upload_hook} = $PREF{disable_upload_hook} =~ /no/i && $PREF{cgi_supports_upload_hook} =~ /yes/i ? 'yes' : 'no';
# Do any actions that are independent of userdir. For example when
# calling filechucker.cgi?js, we don't care about the userdir, and
# if url_without_userdir_is_error is set, it won't work if we check
# for ?js after checking for the userdir.
#
if($qs eq 'js')
{
print "Content-type: text/javascript\n\n";
print get_js();
exit;
}
elsif($qs eq 'css')
{
print "Content-type: text/css\n\n";
print get_css();
exit;
}
elsif($qs eq 'makePasswordHash')
{
make_password_hash();
exit;
}
elsif($qs =~ /(?:^login$|action=login&target=(.+?)(&|$))/)
{
do_login($1);
exit;
}
elsif($qs eq 'logout')
{
do_logout();
exit;
}
elsif($qs =~ /(?:^|&)error=(toobig)&size=(\d+)(?:&|$)/)
{
print_error($1,$2);
exit;
}
# Get the userdir from the URL or the user's cookie. If those prefs are disabled
# or the data wasn't present, returns null, so uploaded_files_dir is unchanged.
#
my $user_subdir = get_userdir();
if($user_subdir)
{
foreach my $dir ($PREF{uploaded_files_dir}, $PREF{uploaded_files_urlpath})
{
if($dir =~ m!(\\|/)$!) { $dir .= $user_subdir . $1; }
else { $dir .= '/' . $user_subdir; }
}
}
my $rht = $ENV{HTTP_HOST}; $rht =~ s/^w{3}\.//i; $rht =~ s/^(?:[^\.]+\.)+([^\.]+\.[^\.]+)$/$1/;
if($ENV{HTTP_HOST} =~ /\./ && $rht && $ENV{HTTP_HOST} =~ /[A-Za-z]/)
{
unless((crypt($rht,'NS') eq 'NSW6MDFyp3i1I')) { print "Content-type: text/html\n\n"; print "\n"; exit; }
}
if($PREF{uploaded_files_dir_is_in_docroot} eq 'yes')
{
$PREF{uploaded_files_realpath} = $PREF{DOCROOT} . $PREF{uploaded_files_dir};
$PREF{uploaded_files_urlpath} = $PREF{uploaded_files_dir};
}
else
{
$PREF{uploaded_files_realpath} = $PREF{uploaded_files_dir};
# They must specify uploaded_files_urlpath in this case.
#($PREF{uploaded_files_urlpath}) = ($ENV{SCRIPT_NAME} =~ m!^((.*)/).+!);
#$PREF{uploaded_files_urlpath} .= $PREF{uploaded_files_dir};
}
# create a $PREF{uploaded_files_realpath_static} which does NOT include any userdir.
$PREF{uploaded_files_realpath_static} = $PREF{uploaded_files_realpath};
$PREF{uploaded_files_realpath_static} =~ s!$user_subdir(/|\\)?$!! if $user_subdir;
unless($PREF{use_database_for_temp_data} =~ /yes/i)
{
if($PREF{datadir_is_in_docroot} eq 'yes')
{
$PREF{datadir} = $PREF{DOCROOT} . $PREF{datadir};
}
else
{
# For 'absolute' and 'relative' we can just use the values as they are.
}
}
if(! -d $PREF{DOCROOT})
{
die "Error: you have set \$PREF{DOCROOT} to '$PREF{DOCROOT}', \nbut that path does not exist.\n";
}
if(! -d $PREF{uploaded_files_realpath})
{
if($user_subdir)
{
if($PREF{auto_create_userdirs} =~ /yes/i)
{
create_dir_if_DNE($PREF{uploaded_files_realpath}, 0777);
}
else
{
die qq`Error: user subdir "$user_subdir" does not exist.\n`;
}
}
else
{
die "Error: your settings for \$PREF{uploaded_files_dir} and \$PREF{uploaded_files_dir_is_in_docroot} \nresult in \$PREF{uploaded_files_realpath} being set to '$PREF{uploaded_files_realpath}', \nbut that path does not exist.\n";
}
}
unless($PREF{use_database_for_temp_data} =~ /yes/i)
{
if(! -d $PREF{datadir})
{
die "Error: your settings for \$PREF{datadir} and \$PREF{datadir_is_in_docroot} \nresult in \$PREF{datadir} being set to '$PREF{datadir}', \nbut that path does not exist.\n";
}
die "Error: the directory \$PREF{datadir} ($PREF{datadir}) must be world-readable, but it isn't.\n" if ! -r $PREF{datadir};
die "Error: the directory \$PREF{datadir} ($PREF{datadir}) must be world-writable, but it isn't.\n" if ! -w $PREF{datadir};
if( ((my $mode = sprintf "%04o", ((stat( "$PREF{datadir}" ))[2] & 07777)) ne '0777') && ($PREF{ignore_chmod_errors} !~ /yes/i) )
{
die qq`Error: the directory \$PREF{datadir} ($PREF{datadir}) must be chmodded 0777, but it's currently $mode.`
. qq`\nIn rare cases, some servers may not report 0777 even though the folder is chmodded correctly.`
. qq`\nIf you're SURE you've chmodded it to 0777 (a+rwx, or "world-readable, -writable, and -executable"),`
. qq`\nthen add \$PREF{ignore_chmod_errors} = 'yes'; near the top of this script and try again.\n`;
}
}
die "Error: the directory \$PREF{uploaded_files_realpath} ($PREF{uploaded_files_realpath}) must be world-readable, but it isn't.\n" if ! -r $PREF{uploaded_files_realpath};
die "Error: the directory \$PREF{uploaded_files_realpath} ($PREF{uploaded_files_realpath}) must be world-writable, but it isn't.\n" if ! -w $PREF{uploaded_files_realpath};
if( ((my $mode = sprintf "%04o", ((stat( "$PREF{uploaded_files_realpath}" ))[2] & 07777)) ne '0777') && ($PREF{ignore_chmod_errors} !~ /yes/i) )
{
die qq`Error: the directory \$PREF{uploaded_files_realpath} ($PREF{uploaded_files_realpath}) must be chmodded 0777, but it's currently $mode.`
. qq`\nIn rare cases, some servers may not report 0777 even though the folder is chmodded correctly.`
. qq`\nIf you're SURE you've chmodded it to 0777 (a+rwx, or "world-readable, -writable, and -executable"),`
. qq`\nthen add \$PREF{ignore_chmod_errors} = 'yes'; near the top of this script and try again.\n`;
}
if($PREF{enable_userdir_from_cookie} =~ /yes/i && !$PREF{userdir_cookie_name})
{
die qq`Error: if you use \$PREF{enable_userdir_from_cookie},\nthen you must also set $PREF{userdir_cookie_name}.\n`;
}
$PREF{allow_unsafe_subdir_names} = 'no' unless exists $PREF{allow_unsafe_subdir_names};
$PREF{delete_logfiles_immediately} = 'yes' unless exists $PREF{delete_logfiles_immediately};
$PREF{allow_files_without_extensions} = 'yes' unless exists $PREF{allow_files_without_extensions};
#$PREF{dir_icon} = '[DIR]' unless exists $PREF{dir_icon};
#$PREF{file_icon} = '[FILE]' unless exists $PREF{file_icon};
#$PREF{up_icon} = '[UP]' unless exists $PREF{up_icon};
expand_custom_vars_in_prefs(\%PREF);
# These are still experimental:
$PREF{use_single_log_backend} = 'no';
}
sub load_styles()
{
my $currentstyle = get_current_filelist_style();
foreach my $key (keys %PREF)
{
if($key =~ /(.+)___(filelist_row_.+)/)
{
my ($style, $pref) = ($1, $2);
$PREF{$pref} = $PREF{$key} if $style eq $currentstyle;
}
}
$PREF{title} = $PREF{"${currentstyle}_title"} if exists $PREF{"${currentstyle}_title"};
$PREF{filelist_row_hover_bgcolor} = $PREF{"${currentstyle}___filelist_row_hover_bgcolor_highcontrast"} if high_contrast_filelist_enabled();
}
sub get_js
{
$qs = undef if $qs eq 'js';
my $qs_without_items = $qs;
$qs_without_items =~ s/(?:^|&)items=\d+(?:&|$)//g;
$qs_without_items =~ s/&&/&/g;
$qs_without_items .= '&' if $qs_without_items;
my $js = qq`
var theRequest = false;
var total_upload_size = 1;
var force_KB_size = ` . ($PREF{force_KB_for_size_display} =~ /yes/i ? 1 : 0) . qq`
var force_KB_rate = ` . ($PREF{force_KB_for_transfer_rate_display} =~ /yes/i ? 1 : 0) . qq`
function goajax(page)
{
theRequest = false;
if(window.XMLHttpRequest)
{
theRequest = new XMLHttpRequest();
if(theRequest.overrideMimeType)
{
theRequest.overrideMimeType('text/xml');
}
}
else if(window.ActiveXObject)
{
try
{
theRequest = new ActiveXObject("Msxml2.XMLHTTP");
} catch (e) {
try
{
theRequest = new ActiveXObject("Microsoft.XMLHTTP");
} catch (e) {}
}
}
if(!theRequest)
{
alert('Your upload is in progress and will probably complete successfully, but your browser cannot display the progress bar (most likely because it is too old). Please wait while your upload completes.');
return false;
}
theRequest.onreadystatechange = updateProgress;
theRequest.open('GET', page, true);
theRequest.send(null);
}
function updateProgress()
{
if(theRequest)
{
if(theRequest.readyState == 4)
{
if(theRequest.status == 200)
{
var rawdata = theRequest.responseText.match(/<data>(.+)<\\/data>/);
` . ($PREF{debug} ? qq`document.getElementById('debug').innerHTML = document.getElementById('debug').innerHTML + '<br /><br />' + rawdata[1];` : '') . qq`
var update = new Array();
update = rawdata[1].split('|');
if(update[1] != 0)
{
total_upload_size = update[1];
}
if(update[5] == 'toobig')
{
location.href="$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_errorpage}?error=toobig&size=" + total_upload_size;
}
var completed_upload_size = update[0];
var elapsedtime = update[2];
var numfinishedfiles = update[3];
var numtotalfiles = update[4];
if(isNum(total_upload_size) && isNum(completed_upload_size) && isNum(elapsedtime) && isNum(numfinishedfiles) && isNum(numtotalfiles))
{
document.getElementById('progStatus').innerHTML = 'Uploading; please wait.';
var progressPercent = Math.ceil((completed_upload_size/total_upload_size)*100);
if(isNum(progressPercent)) { document.getElementById('progPercent').innerHTML = progressPercent + '%'; document.title = progressPercent + '% Complete [Uploading]'; }
var barwidth = parseInt(progressPercent*$PREF{progress_bar_width}/100);
if(isNum(barwidth)) { document.getElementById('progBarDone').style.width = barwidth + 'px'; }
var totaltime = parseInt((elapsedtime * 100) / progressPercent);
var totaltime_forprint = format_timespan_with_unit(totaltime, ' ');
var remainingtime_forprint = format_timespan_with_unit(eval(totaltime - elapsedtime), ' ');
var elapsedtime_forprint = format_timespan_with_unit(elapsedtime, ' ');
var force_MB = total_upload_size > 999999 ? 1 : 0;
var total_upload_size_forprint = format_filesize_with_unit(total_upload_size, ' ', force_MB, force_KB_size);
var remaining_upload_size_forprint = format_filesize_with_unit(total_upload_size - completed_upload_size, ' ', force_MB, force_KB_size);
var completed_upload_size_forprint = format_filesize_with_unit(completed_upload_size, ' ', force_MB, force_KB_size);
var transfer_rate = format_filesize_with_unit(completed_upload_size/elapsedtime, ' ', force_MB, force_KB_rate);
if((completed_upload_size != "") && (completed_upload_size != 0))
{
` . ($PREF{show_progress_table_during_uploads} =~ /yes/i ? qq`
document.getElementById('donet').innerHTML = elapsedtime_forprint;
document.getElementById('dones').innerHTML = completed_upload_size_forprint;
document.getElementById('donef').innerHTML = numfinishedfiles;
document.getElementById('leftt').innerHTML = remainingtime_forprint;
document.getElementById('lefts').innerHTML = remaining_upload_size_forprint;
document.getElementById('leftf').innerHTML = numtotalfiles - numfinishedfiles;
document.getElementById('totalt').innerHTML = totaltime_forprint;
document.getElementById('totals').innerHTML = total_upload_size_forprint;
document.getElementById('totalf').innerHTML = numtotalfiles;
` : undef) . qq`
document.getElementById('progRate').innerHTML = transfer_rate + '/s';
}
if(progressPercent == 100)
{
document.getElementById('theMeter').style.position = 'absolute';
document.getElementById('theMeter').style.left = '-10000px';
document.getElementById('theMeter').style.overflow = 'hidden';
document.getElementById('theMeter').style.height = '0';
document.getElementById('uploadCompleteMsg').style.position = 'relative';
document.getElementById('uploadCompleteMsg').style.left = '0';
document.getElementById('uploadCompleteMsg').style.height = 'auto';
document.getElementById('uploadCompleteMsg').innerHTML = '$PREF{server_processing_upload_message}';
` . ($PREF{show_progress_table_during_uploads} =~ /yes/i ? qq`
document.getElementById('donet').innerHTML = totaltime_forprint;
document.getElementById('dones').innerHTML = total_upload_size_forprint;
document.getElementById('donef').innerHTML = numtotalfiles;
document.getElementById('leftt').innerHTML = '00:00:00';
document.getElementById('lefts').innerHTML = '0.0 $PREF{MB}';
document.getElementById('leftf').innerHTML = '0';
` : undef) . qq`
return null;
}
}
var timeout = navigator.userAgent.indexOf("Safari") == -1 ? 700 : 2200;
var now = new Date();
window.setTimeout("goajax('" + document.getElementById('theuploadform').action + "&action=get_progress_and_size&foo=" + now.getTime() + "')", timeout);
}
else
{
` . ($PREF{debug} ? qq`alert('Error: got a not-OK status code...');` : undef) . qq`
// assume it was a temporary network problem and continue, but at a lower rate.
var now = new Date();
window.setTimeout("goajax('" + document.getElementById('theuploadform').action + "&action=get_progress_and_size&foo=" + now.getTime() + "')", 5000);
}
}
}
}
function startupload()
{
if(check_for_required_fields())
{
update_numitems();
document.getElementById('theuploadform').submit();
document.getElementById('progBarContainer').style.position = 'relative';
document.getElementById('progBarContainer').style.left = '0';
document.getElementById('progBarContainer').style.height = 'auto';
document.getElementById('uploadbutton').disabled = true;
` . ($PREF{debug} ? qq`\tdocument.getElementById('debug').innerHTML = '<span style="font-size: 90%;">get_progress_and_size() return values (via AJAX):<br /><br />(format: progress|total-size|elapsed-time|files-done|num-files)</span><br />'` : '') . qq`
` . ($PREF{clear_page_during_upload} =~ /yes/i ? qq`\tdocument.getElementById('theuploadform').style.position = 'absolute';\n\tdocument.getElementById('theuploadform').style.left = '-10000px';\n\tdocument.getElementById('theuploadform').style.overflow = 'hidden';\n\tdocument.getElementById('theuploadform').style.height = '0';\n\tdocument.getElementById('theuploadform').style.display = 'none'; /* IE doesn't properly hide everything under HTML 4.01 Transitional without display:none, and it doesn't hurt Safari as long as the absolute positioning move still happens. */` : '') . qq`
var timeout = navigator.userAgent.indexOf("Safari") == -1 ? 1200 : 4200;
//window.setTimeout("goajax('$ENV{SCRIPT_NAME}?` . ($qs ? "$qs&" : undef) . qq`serial=$PREF{serial}&action=get_progress_and_size')", timeout);
var now = new Date();
window.setTimeout("goajax('" + document.getElementById('theuploadform').action + "&action=get_progress_and_size&foo=" + now.getTime() + "')", timeout);
}
else { return false; }
}
function startorder()
{
var inputs = document.getElementById('theorderform').getElementsByTagName('input');
var missing = 0;
var i = 0;
for(i = 0; i < inputs.length; i++)
{
if(inputs[i].className.indexOf('required') != -1 && (inputs[i].value == '' || inputs[i].value == undefined))
{
missing = 1;
}
}
if(missing)
{
alert('Please fill in the required fields.');
}
else
{
document.getElementById('theorderform').submit();
}
}
function check_for_required_fields()
{
var onlyinputs = document.getElementById('theuploadform').getElementsByTagName('input');
var selects = document.getElementById('theuploadform').getElementsByTagName('select');
var textareas = document.getElementById('theuploadform').getElementsByTagName('textarea');
var inputs = new Array;
var i = 0;
for(i = 0; i < onlyinputs.length; i++)
{
inputs[i] = onlyinputs[i];
}
var j = 0;
for(j = 0; j < selects.length; j++)
{
inputs[i + j] = selects[j];
}
var k = 0;
for(k = 0; k < textareas.length; k++)
{
inputs[i + j + k] = textareas[k];
}
var items_missing = 0;
var email_format_incorrect = 0;
for(i = 0; i < inputs.length; i++)
{
if(inputs[i].className.indexOf('required') != -1 && (inputs[i].value == '' || inputs[i].value == undefined))
{
inputs[i].style.background = '$PREF{bgcolor_for_unfilled_required_fields}';
inputs[i].style.color = '$PREF{textcolor_for_unfilled_required_fields}';
items_missing = 1;
}
else if(inputs[i].className.indexOf('emailformat') != -1 && !inputs[i].value.match( /.+\@.+\\..+/ ))
{
inputs[i].style.background = '$PREF{bgcolor_for_unfilled_required_fields}';
inputs[i].style.color = '$PREF{textcolor_for_unfilled_required_fields}';
email_format_incorrect = 1;
}
else
{
inputs[i].style.background = '$PREF{default_bgcolor_for_required_fields}';
inputs[i].style.color = '$PREF{default_textcolor_for_required_fields}';
}
}
if(items_missing)
{
alert("Please fill in the required item(s).");
}
else if(email_format_incorrect)
{
alert("Please enter a valid email address.");
}
else
{
return 1;
}
return 0;
}
function format_filesize_with_unit(num,space,forceMB,forceKB)
{
if(!isNum(num,1)) { return "?" + space + "$PREF{KB}"; }
var unit;
if( ((num > 999999) || forceMB) && !forceKB)
{
num = num/(1024*1024);
num = num.toString();
var testnum = num.replace( /^(\\d+\\.\\d).*/, '\$1' ); // show 1 decimal place. // extra escaping b/c printing JS from Perl.
if(testnum == '0.0')
{
testnum = num.replace( /^(\\d+\\.\\d\\d).*/, '\$1' ); // show 2 decimal places.
}
if(testnum == '0.00')
{
testnum = num.replace( /^(\\d+\\.\\d\\d\\d).*/, '\$1' ); // show 3 decimal places.
}
num = testnum;
unit = '$PREF{MB}';
}
else
{
num = parseInt(num/(1024));
unit = '$PREF{KB}';
}
return num + space + unit;
}
function format_timespan_with_unit(num,space)
{
if(!isNum(num)) { return "00:00:00"; }
if(num >= (60*60))
{
var secs_left = num % (60*60);
var mins_left = secs_left / 60;
mins_left = mins_left.toString();
mins_left = mins_left.replace( /^(\\d+)\\..*/, '\$1' ); // show no decimal places. // extra escaping b/c printing JS from Perl.
mins_left = mins_left.replace( /^(\\d)\$/, '0\$1' ); // for single-digits, prepend a zero.
num = num/(60*60);
num = num.toString();
num = num.replace( /^(\\d+)\\..*/, '\$1' ); // show no decimal places.
num = num + ':' + mins_left + ':00';
}
else if(num >= 60)
{
var secs_left = num % 60;
secs_left = secs_left.toString().replace( /^(\\d)\$/, '0\$1' ); // for single-digits, prepend a zero.
num = num/60;
num = num.toString();
num = num.replace( /^(\\d+)\\..*/, '\$1' ); // show no decimal places. // extra escaping b/c printing JS from Perl.
num = num.replace( /^(\\d)\$/, '0\$1' ); // for single-digits, prepend a zero.
num = '00:' + num + ':' + secs_left;
}
else
{
num = num.toString();
num = num.replace( /^(\\d+)\\..*/, '\$1' ); // show no decimal places. // extra escaping b/c printing JS from Perl.
num = num.replace( /^(\\d)\$/, '0\$1' ); // for single-digits, prepend a zero.
num = '00:00:' + num;
}
return num;
}
function isNum(testval,decimalsOK)
{
if(typeof(testval) == 'undefined') return false;
testval = testval.toString();
if (!testval.length) return false;
var numbers = decimalsOK ? '.0123456789' : '0123456789';
for (i=0; i<testval.length; i++)
{
if (numbers.indexOf(testval.charAt(i),0) == -1) return false;
}
return true;
}
function update_form_fields()
{
location.href="$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_uploader}?${qs_without_items}items=" + document.getElementById("itemcount").value;
}
// In case the user set the form to N files, but then didn't populate all of them.
function update_numitems()
{
var inputs = document.getElementById('theuploadform').getElementsByTagName('input');
var populated_file_elements = 0;
var i = 0;
for(i = 0; i < inputs.length; i++)
{
if(inputs[i].type == 'file' && inputs[i].value != '' && inputs[i].value != undefined)
{
populated_file_elements++;
}
}
document.getElementById('numitems').value = populated_file_elements;
document.getElementById('totalf').innerHTML = populated_file_elements;
document.getElementById('leftf').innerHTML = populated_file_elements;
document.getElementById('theuploadform').action = document.getElementById('theuploadform').action.toString().replace( /items=\\d+/, 'items=' + populated_file_elements );
}
function set_cookie(name, value, hours_to_live, path, domain, secure)
{
var expireDate = "";
if(hours_to_live)
{
expireDate = (new Date((new Date()).getTime() + hours_to_live*3600000)).toGMTString();
}
var curCookie = name + "=" + escape(value) +
((hours_to_live) ? "; expires=" + expireDate : "") +
((path) ? "; path=" + path : "") +
((domain) ? "; domain=" + domain : "") +
((secure) ? "; secure" : "");
document.cookie = curCookie;
}
function get_cookie(name)
{
var dc = document.cookie;
var prefix = name + "=";
var begin = dc.indexOf("; " + prefix);
if (begin == -1) {
begin = dc.indexOf(prefix);
if (begin != 0) return null;
} else
begin += 2;
var end = document.cookie.indexOf(";", begin);
if (end == -1)
end = dc.length;
return unescape(dc.substring(begin + prefix.length, end));
}
function delete_cookie(name, path, domain)
{
if(get_cookie(name))
{
document.cookie = name + "=" +
((path) ? "; path=" + path : "") +
((domain) ? "; domain=" + domain : "") +
"; expires=Thu, 01-Jan-70 00:00:01 GMT";
}
else
{
alert('$PREF{no_selections_text}');
}
}
function select_item(newvalue)
{
var set_it = 1;
var oldvalue = get_cookie('$PREF{selection_cookie_name}');
if(oldvalue)
{
if(oldvalue.indexOf(newvalue) != -1)
{
if(window.confirm('$PREF{duplicate_item_text}'))
{
set_it = 1;
}
else
{
set_it = 0;
}
}
newvalue = oldvalue + ':|:|:' + newvalue;
}
if(set_it)
{
set_cookie('$PREF{selection_cookie_name}', newvalue, 168, '/');
}
}
function clear_selections()
{
if(get_cookie('$PREF{selection_cookie_name}'))
{
if(window.confirm('$PREF{clear_selections_verification_text}'))
{
delete_cookie('$PREF{selection_cookie_name}', '/');
}
}
else
{
alert('$PREF{no_selections_text}');
}
}
function set_row_mouseovers()
{
if(document.getElementById("filelist"))
{
var filelist_rows = document.getElementById("filelist").getElementsByTagName("tr");
var i = 0;
for(i = 0; i < filelist_rows.length; i++)
{
filelist_rows[i].onmouseover = setbg;
if((i % 2)==0)
{
filelist_rows[i].onmouseout = unsetbgeven;
}
else
{
filelist_rows[i].onmouseout = unsetbgodd;
}
}
}
}
function setbg()
{
this.style.background = '$PREF{filelist_row_hover_bgcolor}';
//this.style.border = '$PREF{filelist_row_hover_border}';
` . (high_contrast_filelist_enabled() ? qq`
var tds = this.getElementsByTagName("td");
var i = 0;
for(i = 0; i < tds.length; i++)
{
tds[i].style.color = '$PREF{filelist_row_hover_text_color}';
if(tds[i].getElementsByTagName("a"))
{
var links = tds[i].getElementsByTagName("a");
var j = 0;
for(j = 0; j < links.length; j++)
{
links[j].style.color = '$PREF{filelist_row_hover_link_color}';
}
}
}
` : undef) . qq`
}
function unsetbgeven()
{
this.style.background = '$PREF{filelist_row_normal_bgcolor_even}';
//this.style.border = '$PREF{filelist_row_normal_border}';
` . (high_contrast_filelist_enabled() ? qq`unsettext(this);` : undef) . qq`
}
function unsetbgodd()
{
this.style.background = '$PREF{filelist_row_normal_bgcolor_odd}';
//this.style.border = '$PREF{filelist_row_normal_border}';
` . (high_contrast_filelist_enabled() ? qq`unsettext(this);` : undef) . qq`
}
function unsettext(myself)
{
var tds = myself.getElementsByTagName("td");
var i = 0;
for(i = 0; i < tds.length; i++)
{
tds[i].style.color = '$PREF{filelist_row_normal_text_color}';
if(tds[i].getElementsByTagName("a"))
{
var links = tds[i].getElementsByTagName("a");
var j = 0;
for(j = 0; j < links.length; j++)
{
links[j].style.color = '$PREF{filelist_row_normal_link_color}';
}
}
}
}
function schedule_onload_action(newfunc)
{
var already_scheduled = window.onload;
if(typeof window.onload != 'function')
{
window.onload = newfunc;
}
else
{
window.onload = function()
{
already_scheduled();
newfunc();
}
}
}
schedule_onload_action(set_row_mouseovers);
`;
return $js;
}
sub get_css
{
my $css = qq`
#fcbody { background: #ddd; font-family: sans-serif; font-size: 90%; text-align: center; }
#fcbody dl { margin: 0 0 1em; padding: 0; }
#fcbody dt, dd { margin: 0; padding: 0; }
#pb { margin: 14px auto 2px auto; padding: 3px; }
#pb a { color: #000; }
#pb a:hover { color: #aaa; }
#pb { position: absolute; left: -8000px; }
#fcfooter { color: #8b8f8b; margin: 24px auto 4px auto; }
/* #uploaderpage, #filelistpage, #defaultpage etc, are the outer containers for their respective pages. */
#uploaderpage, #uploadcompletepage, #filelistpage, #defaultpage { width: 700px; margin: 15px auto; background: white; border: 1px solid #999; padding: 10px; }
#uploaderpage #title, #uploadcompletepage #title, #filelistpage #title, #defaultpage #title { font-size: 200%; font-weight: bold; padding: 8px; }
#uploaderpage { width: 500px; }
#uploaderpage #intro { text-align: justify; }
#fc-container { padding: 8px 12px; } /* this is the whole page except for title and pb */
#fc-container a { color: #507090; }
#fc-container a:hover { color: #aaa; }
/* #progBarContainer includes everything (progress bar, text, table); #theMeter includes just the bar and the text (percent and rate) */
#progBarContainer { padding-top: 10px; }
#progBar, #progBarText { width: $PREF{progress_bar_width}px; }
#progBar { margin: 2px auto; height: 20px; border: 1px inset; background: #eee; text-align: left; }
#progBarDone { width: 0; height: 20px; border-right: 1px solid #444; background: #507090; /* background: url(/layout/filechucker-scrolling-bg-08.gif) repeat-x; */ }
#theMeter, #uploadCompleteMsg { margin-bottom: 20px; }
#progBarContainer table { width: $PREF{progress_bar_width}px; margin: 4px auto 20px auto; text-align: right; border-collapse: collapse; border: 0; border-bottom: 1px solid #bbb;}
#progBarContainer table td { border-top: 1px solid #bbb; text-align: center; }
#progBarContainer #upload-row-1, #progBarContainer #upload-row-3 { background: #e6e6e6; }
#progBarContainer #upload-row-2, #progBarContainer #upload-row-4 { background: #efefef; }
#progBarText { font-size: 90%; margin: 1px auto; white-space: nowrap; }
#progRate { float: left; text-align: left; width: 19%; }
#progStatus { float: left; text-align: center; width: 70%; font-style: italic; }
#progPercent { float: right; text-align: right; width: 10%; }
#uploadsummary { margin-top: 20px; margin-bottom: 20px !important; }
#uploadsummary .file { margin-top: 8px; }
#uploadsummary dt { font-weight: bold; margin-bottom: 10px; }
#uploadstats dt { font-weight: bold; margin-bottom: 10px; }
td.headercell { font-weight: bold; }
`
. (
($PREF{using_upload_hook} =~ /yes/i)
?
qq`#tca1,#tcb1,#tcc1,#tcd1 { width: 25%; }`
. qq`\n#tca2,#donef,#leftf,#totalf { width: 25%; }`
. qq`\n#tca3,#dones,#lefts,#totals { width: 25%; }`
. qq`\n#tca4,#donet,#leftt,#totalt { width: 25%; }`
:
qq`#tca1,#tcb1,#tcc1,#tcd1 { width: 33%; }`
. qq`\n#tca2,#donef,#leftf,#totalf { position: absolute; left: -10000px; overflow: hidden; height: 0; }`
. qq`\n#tca3,#dones,#lefts,#totals { width: 34%; }`
. qq`\n#tca4,#donet,#leftt,#totalt { width: 33%; }`
)
. qq`
#viewpath { font-weight: bold; margin-bottom: 15px; }
#filelist { text-align: left; border-collapse: collapse; margin: 2px auto; border: 1px solid #444; }
#filelist tr { border: 0px solid white; }
#filelist tr.even { background: $PREF{filelist_row_normal_bgcolor_even}; }
#filelist tr.odd { background: $PREF{filelist_row_normal_bgcolor_odd}; }
#filelist td { }
#filelist a:link { color: $PREF{filelist_row_normal_link_color}; text-decoration: none; display: block; width: 100%; padding: 4px 2px; }
#filelist a:visited { color: $PREF{filelist_row_visited_link_color}; text-decoration: none; display: block; width: 100%; padding: 4px 2px; }
#filelist a:hover { color: $PREF{filelist_row_hover_link_color}; }
#filelist img { position: absolute; left: -10000px; }
#filelist td.pname { background: url($PREF{path_to_filelist_images}fcarrow.gif) 1% 50% no-repeat; background-color: inherit; }
#filelist td.dname { background: url($PREF{path_to_filelist_images}fcfolder.gif) 1% 50% no-repeat; background-color: inherit; }
#filelist td.fname { background: url($PREF{path_to_filelist_images}fcfile.gif) 1% 50% no-repeat; background-color: inherit; }
#filelist td.pname, #filelist td.dname, #filelist td.fname { width: 340px; padding-left: 20px; }
#filelist .info, #filelist .mv, #filelist .sel, #filelist .del { text-align: center; }
#filelist .size { text-align: right; }
#filelist .size { white-space: pre; padding: 4px 10px 4px 2px; }
#filelist .date { white-space: pre; padding: 4px 5px; text-align: right; }
#filelist .info, #filelist .mv, #filelist .del, #filelist .sel { padding: 0 6px; }
#filelist .spc { padding: 0 6px 0 3px; }
#filelist th { text-align: center; padding: 5px 0; font-size: 120%; background: #507090; border-bottom: 1px solid #444; }
#filelist #namehead { text-align: left; padding-left: 7px; }
#filelist #namehead a, #filelist #sizehead a, #filelist #datehead a { color: #fff; font-weight: bold; }
#setfilecount { margin: 15px 0 12px 0; }
#theuploadform { }
#filefields { border-top: 1px solid #ccc; border-bottom: 1px solid #ccc; border: 1px solid #ccc; /* background: #e3e3e3; */ }
#filefields .even { background: #fff; }
#filefields .odd { /* background: #e3e3e3; */ }
.fileelement { margin-bottom: 5px; }
.onesubgroup { padding: 15px 0 10px 0; }
.onesubgroup div { margin-bottom: 5px; }
.onesubgroup label { display: inline; font-size: 100%; } /* we're centered by default, so we don't need the floats and clearfix-filefield stuff; just inline it. */
#uploadbutton { margin: 14px 0 6px 0; }
.uploader-comments { text-align: left; border: 1px solid #e0e0e0; padding: 4px; }
#fcbody .hr { height: 1px; border-bottom: 1px solid #000; margin: 15px 2px; line-height: 1px; }
#fcbody h1, #fcbody h2, #fcbody h3, #fcbody h4, #fcbody h5, #fcbody h6 { margin-top: 5px; margin-bottom: 5px; }
#fcbody form { margin: 0; padding: 0; }
#fcbody p { margin-top: 10px; margin-bottom: 10px; }
.comments textarea
{
width: 300px; height: 50px;
}
#top-textboxes, #perfile-textboxes, #bottom-textboxes
{
margin: 25px 0;
padding: 5px;
border: 1px solid #ccc;
}
#top-textboxes div, #perfile-textboxes div, #bottom-textboxes div
{
margin: 7px 2px;
}
#top-textboxes-title, #perfile-textboxes-title, #bottom-textboxes-title
{
font-size: 110%;
font-weight: bold;
}
#perfile-textboxes
{
margin: 8px 20px;
}
.textboxes-label
{
float: left;
width: 47%;
text-align: right;
margin-top: 3px !important;
}
#top-textboxes input, #top-textboxes textarea,
#perfile-textboxes input, #perfile-textboxes textarea,
#bottom-textboxes input, #bottom-textboxes textarea
{
float: left;
width: 37%;
display: block;
}
#selections_table
{
border-collapse: collapse;
border: 1px solid #9a9a9a;
margin: 15px auto;
text-align: left;
}
#selections_table .odd { background: #e6e6e6; }
#selections_table .even { background: #efefef; }
#selections_table td { padding: 4px 4px 4px 20px; background: url($PREF{path_to_filelist_images}fcfile.gif) 1% 50% no-repeat; }
#place_order { text-align: center; }
#theorderform { width: 300px; margin: 0 auto; padding: 3px; text-align: left; border: 1px solid #999; background: #e6e6e6; }
#theorderform .text { width: 150px; margin: 5px; padding: 3px; border: 1px solid #676767; }
#theorderform .submit input { margin: 5px; }
.clearfixtb:after {
content: ".";
display: block;
height: 0;
clear: both;
visibility: hidden;
}
.clearfixtb { display: inline-table; }
/* Hides from IE-mac \*/
* html .clearfixtb {height: 1%;}
.clearfixtb {display: block;}
/* End hide from IE-mac */
`;
my %styles = ();
$styles{big} = qq`
/* big blocky style: */
#filelist img { position: absolute; left: -10000px; }
#filelist a:link, #filelist a:visited { }
#filelist th, #filelist td { padding: 10px 6px; }
#filelist th { font-size: 140%; }
#filelist td.pname { background: url($PREF{path_to_filelist_images}fcarrowbig.gif) 1% 50% no-repeat; background-color: inherit; }
#filelist td.dname { background: url($PREF{path_to_filelist_images}fcfolderbig.gif) 1% 50% no-repeat; background-color: inherit; }
#filelist td.fname { background: url($PREF{path_to_filelist_images}fcfilebig.gif) 1% 50% no-repeat; background-color: inherit; }
#filelist td.pname, #filelist td.dname, #filelist td.fname { width: 350px; padding-left: 15px; }
#filelist td.pname a:link, #filelist td.dname a:link, #filelist td.fname a:link, td.pname, #filelist td.pname a:visited { color: black; font-size: 14px; font-weight: bold; text-decoration: none; }
#filelist td.dname a:visited, #filelist td.fname a:visited { color: #000; font-size: 14px; font-weight: bold; text-decoration: none; }
#filelist td.pname a:hover, #filelist td.dname a:hover, #filelist td.fname a:hover { }
#filelist td.dname { padding-top: 12px; padding-bottom: 8px; }
`;
$styles{dark} = qq`
#fcbody { background: #434343; color: #fff; }
#title { padding-top: 20px !important; color: #fff; }
#intro { margin: 0 7px; }
#fc-container a { color: #ccc; }
#fc-container a:hover { color: #000; }
#uploaderpage, #uploadcompletepage, #filelistpage, #defaultpage { background: #5a775a; background: #5a775a; border: 0px; padding: 0; padding-bottom: 10px; }
#fc-container { padding: 0; margin: 0; }
#uploaderpage { width: 600px; padding-top: 12px; }
#uploadbuttonwrapper { margin: 15px 5px; }
#progBarContainer table { color: #fff; background: #424242; border-top: 1px solid #000; border-left: 1px solid #000; border-bottom: 1px solid #fff; border-right: 1px solid #fff; }
#progBarContainer #upload-row-1, #progBarContainer #upload-row-3 { background: #545454; }
#progBarContainer #upload-row-2, #progBarContainer #upload-row-4 { background: #545454; }
#progBarContainer table td#tca1,#progBarContainer table td#tca2,#progBarContainer table td#tca3,#progBarContainer table td#tca4 { border-top: 0; }
#dones,#lefts,#totals,#donef,#leftf,#totalf,#donet,#leftt,#totalt { border-top: 1px solid #676767; }
#progBar { background: #6a6a6a; border-top: 1px solid #000; border-left: 1px solid #000; border-bottom: 1px solid #fff; border-right: 1px solid #fff; }
#progBarDone { border-right: 1px solid #000; background: #993333; }
#filefields { background: #333; background: transparent; color: #000; margin: 0px 20px; border: 1px solid #393939; }
#filefields .even { background: #5a6d5a; }
#filefields div { margin-top: 8px; margin-bottom: 12px; }
.onesubgroup { padding: 3px 0; }
table#filelist { color: $PREF{filelist_row_normal_text_color}; border: 1px solid #333; border-bottom: 1px solid #333; margin: 0 auto 20px auto; }
#filelist th { background: #333; border-bottom: 0px solid #000; }
#filelist td { border-top: 1px solid #676767; }
#filelist a:hover { color: #fff; }
#fcfooter { background: #333; margin-top: 0; padding: 10px 4px; }
#fcfooter a { color: #fff; text-decoration: none; font-weight: bold; }
#fcfooter a:hover { color: #aa3333; }
`;
$styles{darker} = qq`
#fcbody { background: #434343; color: #fff; }
#title { color: #fff; }
#fc-container a { color: #aaa; }
#fc-container a:hover { color: #fff; }
#uploaderpage, #uploadcompletepage, #filelistpage, #defaultpage { background: #575757; border: 0; border-top: 1px solid #fff; border-left: 1px solid #fff; border-bottom: 1px solid #000; border-right: 1px solid #000; }
#progBarContainer table { color: #fff; background: #424242; border-top: 1px solid #000; border-left: 1px solid #000; border-bottom: 1px solid #fff; border-right: 1px solid #fff; }
#progBarContainer #upload-row-1, #progBarContainer #upload-row-3 { background: #424242; }
#progBarContainer #upload-row-2, #progBarContainer #upload-row-4 { background: #4a4a4a; }
#progBarContainer table td { border: 0; }
#progBar { background: #424242; border-top: 1px solid #000; border-left: 1px solid #000; border-bottom: 1px solid #fff; border-right: 1px solid #fff; }
#progBarDone { border-right: 1px solid #444; background: #4a774a; }
#filefields { border: 0px solid #393939; background: #4a774a; color: black; border-top: 1px solid #000; border-left: 1px solid #000; border-bottom: 1px solid #fff; border-right: 1px solid #fff; }
#filefields div { margin-top: 8px; margin-bottom: 12px; }
table#filelist { border: 0px solid #000; color: $PREF{filelist_row_normal_text_color}; border-top: 1px solid #000; border-left: 1px solid #000; border-bottom: 1px solid #fff; border-right: 1px solid #fff; }
#filelist th { background: #437743; border-bottom: 0px solid #000; }
/* input,select { background: #000; color: #fff; border: 2px inset #fff; } */
`;
$styles{minimal} = qq`
/* minimal style: */
#fcbody { background: #fff; font-family: serif; }
#uploaderpage, #uploadcompletepage, #filelistpage, #defaultpage { border: 0; }
#filelistpage #title { position: absolute; left: -10000px; }
#fcfooter { color: #555; }
#fcfooter a { color: #000; }
#fcfooter a:hover { color: #507090; }
#pb a { color: #737373; }
#pb a:hover { color: #000; }
#uploader { background: #fff; border: 0; }
#filelist { border: 1px dashed #bbb; border-left: 0; border-right: 0; }
#filelist tr { border-top: 1px dashed #bbb; }
#filelist tr.even { background: $PREF{filelist_row_normal_bgcolor_even}; background: #fff; }
#filelist tr.odd { background: $PREF{filelist_row_normal_bgcolor_odd}; background: #fff; }
#filelist img { position: absolute; left: -10000px; }
#filelist a:link, #filelist a:visited { }
#filelist th, #filelist td { padding: 1px 6px; font-size: 0.8em; }
#filelist th { font-size: 0.9em; color: #000; background: #fff; border-bottom: 0; }
#filelist #namehead a, #filelist #sizehead a, #filelist #datehead a { color: #000; }
#filelist td.pname { background: url($PREF{path_to_filelist_images}fcarrow.gif) 1% 50% no-repeat; background-color: inherit; }
#filelist td.dname { background: url($PREF{path_to_filelist_images}fcfolder.gif) 1% 50% no-repeat; background-color: inherit; }
#filelist td.fname { background: url($PREF{path_to_filelist_images}fcfile.gif) 1% 50% no-repeat; background-color: inherit; }
#filelist td.pname, #filelist td.dname, #filelist td.fname { width: 350px; padding-left: 18px; }
#filelist td.pname a:link, #filelist td.dname a:link, #filelist td.fname a:link, td.pname, #filelist td.pname a:visited { color: black; text-decoration: none; }
#filelist td.dname a:visited, #filelist td.fname a:visited { color: #555; text-decoration: none; }
#filelist td.pname a:hover, #filelist td.dname a:hover, #filelist td.fname a:hover { }
td.size { color: #444; }
td.date { color: #444; }
`;
$styles{round} = qq`
/* round style: */
#uploaderpage, #uploadcompletepage, #filelistpage, #defaultpage { padding: 0; border: 0; }
#fcbody { background: #e3e3e3; font-size: 80%; }
#fcc1 { background: url($PREF{path_to_filelist_images}fcc-TL-e3e3e3.png) top left no-repeat; }
#fcc2 { background: url($PREF{path_to_filelist_images}fcc-TR-e3e3e3.png) top right no-repeat; }
#fcc3 { background: url($PREF{path_to_filelist_images}fcc-BR-e3e3e3.png) bottom right no-repeat; }
#fcc4 { background: url($PREF{path_to_filelist_images}fcc-BL-e3e3e3.png) bottom left no-repeat; }
#title img { margin: 10px auto 0px auto; }
#uploaderpage #title, #uploadcompletepage #title, #filelistpage #title, #defaultpage #title { padding: 1px; }
#fc-container, #intro { margin-top: 0px; padding-top: 0px; }
#uploaderpage #fcfooter { margin-bottom: 15px; font-size: 95%; }
table#filelist { border: 0px solid #ccc; color: #444; width: 630px; margin: 0 auto; }
#filelist th { background: #e3e3e3; border: 0; font-size: 90%; padding: 0px; border-bottom: 1px solid #fff; }
#filelist #namehead a, #filelist #sizehead a, #filelist #datehead a { color: #878787; font-weight: bold; }
#filelist td { border-top: 1px solid #ddd; font-size: 90%; }
#viewpath { background: #efefef url($PREF{path_to_filelist_images}fcc-TL-efefef.png) top left no-repeat; color: #555; color: #63b4cd; color: #53a4cd; margin: 8px auto 0px auto; width: 630px; text-align: left; border-bottom: 1px solid #fff; font-size: 110%; font-family: Tahoma, Arial, sans-serif; letter-spacing: 1px; }
#viewpath-inner { background: url($PREF{path_to_filelist_images}fcc-TR-efefef.png) top right no-repeat; width: 630px; }
#viewpath-text { padding: 10px 15px 10px 15px; }
#filelistpage #fcfooter { background: #efefef url($PREF{path_to_filelist_images}fcc-BR-efefef.png) bottom right no-repeat; color: #444; margin: 0px auto 10px auto; width: 630px; border-top: 1px solid #ddd; font-size: 95%; }
#filelistpage #fcfooter-inner { background: url($PREF{path_to_filelist_images}fcc-BL-efefef.png) bottom left no-repeat; width: 630px; }
#filelistpage #fcfooter-text { padding: 10px; }
#fc-container a { font-weight: bold; }
#fc-container #fcfooter a { color: #65c460; text-decoration: none; }
#fc-container #fcfooter a:hover { background: #65c460; color: white; }
`;
my $stylecookie = get_cookie("fcliststyle");
my @enabled_styles = split /[,\s]+/, $PREF{enabled_styles};
if($PREF{enable_filelist_style_switcher_link} =~ /yes/i)
{
foreach my $style (@enabled_styles)
{
my @other_styles = split /[,\s]+/, $PREF{enabled_styles};
my %other_styles = ();
foreach my $other_style (@other_styles)
{
$other_styles{$other_style} = 1 unless $other_style eq $style;
}
if( ($stylecookie eq $style) || ($PREF{default_filelist_style} eq $style && !$other_styles{$stylecookie}) )
{
$css .= "\n\n" . $styles{$style} . "\n\n";
$PREF{current_filelist_style} = $style;
}
}
}
else
{
foreach my $style (@enabled_styles)
{
if($PREF{default_filelist_style} eq $style)
{
$css .= "\n\n" . $styles{$style} . "\n\n";
$PREF{current_filelist_style} = $style;
}
}
}
$css .= qq`
$PREF{custom_css_section}
`;
return $css;
}
sub high_contrast_filelist_enabled()
{
return current_filelist_style_is_highcontrast();
}
sub current_filelist_style_is_highcontrast()
{
#return (get_current_filelist_style() =~ /^(light)$/);
my $currentstyle = get_current_filelist_style();
if($PREF{"${currentstyle}___filelist_row_hover_bgcolor_highcontrast"} =~ /\S/)
{
return 1;
}
else { return 0; }
}
sub get_current_filelist_style()
{
if($PREF{enable_filelist_style_switcher_link} =~ /yes/i && get_cookie("fcliststyle"))
{
return get_cookie("fcliststyle");
}
else
{
return $PREF{default_filelist_style};
}
}
sub onedecimal
{
my $num = shift;
return $num =~ /^(\d+\.\d).*/ ? $1 : $num;
}
sub list_uploaded_files()
{
unless(user_is_allowed_to('list_files')) { print_needlogin_error_and_exit('list_files'); }
$PREF{on_page} = 'filelist';
delete_old_files();
start_html_output('Uploaded Files', 'css', 'js');
my $dateformat = $PREF{date_format_for_filelist} ? $PREF{date_format_for_filelist} : "%Y-%m-%d, %H:%M";
my $userdir = get_userdir_for_qs();
my $qs_without_sort = $qs;
$qs_without_sort =~ s/(?:^|&)s=(?:n|s|d)r?(?:&|$)//g;
$qs_without_sort =~ s/&+$//g;
my $sort_string_present = $qs =~ /(?:^|&)s=(?:n|s|d)r?(?:&|$)/ ? 1 : 0;
my $column_headers = qq`\n<tr>`
. qq`<th id="namehead"><a href="$PREF{here_filelist}?$qs_without_sort&s=n` . (($qs =~ /(?:^|&)s=n(?:&|$)/ || !$sort_string_present) ? 'r' : undef) . qq`">Name</a></th>`
. qq`<th id="sizehead"><a href="$PREF{here_filelist}?$qs_without_sort&s=s` . ($qs =~ /(?:^|&)s=s(?:&|$)/ ? 'r' : undef) . qq`">Size</a></th>`
. qq`<th id="datehead"><a href="$PREF{here_filelist}?$qs_without_sort&s=d` . ($qs =~ /(?:^|&)s=d(?:&|$)/ ? 'r' : undef) . qq`">Date</a></th>`
. qq`<th id="infohead"></th>`
. (user_is_allowed_to('move_items') && $PREF{enable_subdirs} =~ /yes/i ? qq`<th id="mvhead"></th>` : undef)
. (user_is_allowed_to('delete_items') ? qq`<th id="delhead"></th>` : undef)
. (user_is_allowed_to('order_items') && $PREF{enable_ordering} =~ /yes/i ? qq`<th id="selhead"></th>` : undef)
. qq`<th id="spchead"></th>`
. qq`</tr>`
. qq`\n`;
my (@items,@files,@dirs) = ();
my $num_table_cols = 3;
my $fulldir = $PREF{uploaded_files_realpath};
my $path = ();
if($PREF{enable_subdirs} =~ /yes/i && $qs =~ /(?:^|&)path=(.*?)(?:&|$)/)
{
$path = $1;
enc_urldecode($path);
$path .= '/';
$path = enc_untaint($path,'keep_path');
if($path =~ m!^[/\\]+$!)
{
$path = ();
}
else
{
$fulldir .= '/' . $path;
die "Error: the path you specified ($path) does not exist.\n" unless -d $fulldir;
die "Error: the path you specified ($path) is not writable.\n" unless -w $fulldir;
}
}
if(-d $fulldir)
{
opendir(FILELISTDIRH, $fulldir) or die "$0: couldn't open $fulldir: $!\n";
my $dirh = \*FILELISTDIRH; # voodoo required since ancient Perls can't accept "open(my $foo_fh)".
if($qs =~ /(?:^|&)s=s(?:&|$)/) { @items = grep { !/^(\.|\.\.|\.ht*)$/ } sort { (stat("$fulldir/$a"))[7] <=> (stat("$fulldir/$b"))[7] } readdir($dirh); }
elsif($qs =~ /(?:^|&)s=sr(?:&|$)/) { @items = grep { !/^(\.|\.\.|\.ht*)$/ } sort { (stat("$fulldir/$b"))[7] <=> (stat("$fulldir/$a"))[7] } readdir($dirh); }
elsif($qs =~ /(?:^|&)s=d(?:&|$)/) { @items = grep { !/^(\.|\.\.|\.ht*)$/ } sort { (stat("$fulldir/$a"))[9] <=> (stat("$fulldir/$b"))[9] } readdir($dirh); }
elsif($qs =~ /(?:^|&)s=dr(?:&|$)/) { @items = grep { !/^(\.|\.\.|\.ht*)$/ } sort { (stat("$fulldir/$b"))[9] <=> (stat("$fulldir/$a"))[9] } readdir($dirh); }
elsif($qs =~ /(?:^|&)s=nr(?:&|$)/) { @items = grep { !/^(\.|\.\.|\.ht*)$/ } sort { lc($b) cmp lc($a) } readdir($dirh); }
else { @items = grep { !/^(\.|\.\.|\.ht*)$/ } sort { lc($a) cmp lc($b) } readdir($dirh); }
closedir($dirh) or die "$0: couldn't close $fulldir: $!\n";
}
for(@items)
{
push (@dirs, $_) if ($PREF{enable_subdirs} =~ /yes/i && -d "$fulldir/$_");
push (@files, $_) if -f "$fulldir/$_";
}
if($PREF{enable_subdirs} =~ /yes/i)
{
my $viewing = get_uploaded_files_url_path('without_trailing_slash');
$viewing .= "/$path";
slashify($viewing);
print qq`$PREF{viewpath_markup_start}Viewing: $viewing$PREF{viewpath_markup_end}\n`;
}
else
{
print qq`<h4>Uploaded Files:</h4>\n`;
}
print qq`\n<table id="filelist">\n`;
print $column_headers;
my $path_urlencoded = $path;
urlencode_path_but_leave_slashes($path_urlencoded);
my $i = 1;
if($path)
{
my $test_path = $path;
$test_path =~ s!^/!!g;
$test_path =~ s!/$!!g;
my ($parent_dir) = ($test_path =~ m!(.+)/!);
$parent_dir = () if $parent_dir eq $test_path;
my $parent_dir_url = $parent_dir;
enc_urlencode($parent_dir_url);
$parent_dir_url = '&path=' . $parent_dir_url if $parent_dir_url;
print qq`<tr class="` . ($i % 2 == 0 ? 'even' : 'odd') . qq`"><td class="pname">$PREF{up_icon} <a href="$PREF{here_filelist}?${userdir}action=listfiles$parent_dir_url">Parent Directory</a></td>`;
print qq`<td class="size">--</td>`;
$parent_dir = $parent_dir ? "$PREF{uploaded_files_realpath}/$parent_dir" : $PREF{uploaded_files_realpath}; # must remove trailing slash or stat doesn't work on Win32.
my $mtime = strftime($dateformat, localtime((stat($parent_dir))[9] + $PREF{time_offset}));
my $ctime = strftime($dateformat, localtime((stat($parent_dir))[10] + $PREF{time_offset}));
print qq`<td class="date">$mtime</td>`;
print qq`<td class="info">--</td>` if user_is_allowed_to('view_upload_info') && info_system_is_enabled();
print qq`<td class="mv">--</td>` if user_is_allowed_to('move_items') && $PREF{enable_subdirs} =~ /yes/i;
print qq`<td class="del">--</td>` if user_is_allowed_to('delete_items');
print qq`<td class="sel">--</td>` if user_is_allowed_to('order_items') && $PREF{enable_ordering} =~ /yes/i;
print qq`<td class="spc"></td>`;
print qq`</tr>\n`;
$i++;
}
foreach my $dir (@dirs)
{
my $displayname = $dir;
my $tooltip = ();
if( ($PREF{display_shortened_filename_if_longer_than} =~ /^(\d+)$/) && (length($displayname) > $1) )
{
my $length = $1;
my ($start,$end) = ($displayname =~ /^(.+)(\..+)$/);
$start =~ s/^(.{$length}).*/$1/;
$displayname = length("$start...$end") < length($displayname) ? "$start...$end" : $displayname;
$tooltip = $dir;
}
my $fulldir = "$PREF{uploaded_files_realpath}/$path/$dir";
my ($dir_urlencoded) = ($dir);
enc_urlencode($dir_urlencoded);
print qq`<tr class="` . ($i % 2 == 0 ? 'even' : 'odd') . qq`"><td class="dname">$PREF{dir_icon} <a href="$PREF{here_filelist}?${userdir}action=listfiles&path=$path_urlencoded$dir_urlencoded" title="$tooltip">$displayname</a></td>`;
print qq`<td class="size">--</td>`;
my $mtime = strftime($dateformat, localtime((stat($fulldir))[9] + $PREF{time_offset}));
my $ctime = strftime($dateformat, localtime((stat($fulldir))[10] + $PREF{time_offset}));
print qq`<td class="date">$mtime</td>`;
print qq`<td class="info">--</td>` if user_is_allowed_to('view_upload_info') && info_system_is_enabled();
print qq`<td class="mv"><a href="$PREF{here_filelist}?action=move&folder=$dir_urlencoded&src=$path_urlencoded">mv</a></td>` if user_is_allowed_to('move_items') && $PREF{enable_subdirs} =~ /yes/i;
print qq`<td class="del"><a href="$PREF{here_filelist}?${userdir}action=delete&path=$path_urlencoded&dir=$dir_urlencoded">del</a></td>` if user_is_allowed_to('delete_items');
print qq`<td class="sel">--</td>` if user_is_allowed_to('order_items') && $PREF{enable_ordering} =~ /yes/i;
print qq`<td class="spc"></td>`;
print qq`</tr>\n`;
$i++;
}
foreach my $file (@files)
{
next unless item_is_allowed_to_be_displayed($file);
my $displayname = $file;
my $tooltip = ();
if( ($PREF{display_shortened_filename_if_longer_than} =~ /^(\d+)$/) && (length($displayname) > $1) )
{
my $length = $1;
my ($start,$end) = ($displayname =~ /^(.+)(\..+)$/);
$start =~ s/^(.{$length}).*/$1/;
$displayname = length("$start...$end") < length($displayname) ? "$start...$end" : $displayname;
$tooltip = $file;
}
my ($file_urlencoded) = ($file);
enc_urlencode($file_urlencoded);
my $link = get_download_link($path, $file, $path_urlencoded, $file_urlencoded);
print qq`<tr class="` . ($i % 2 == 0 ? 'even' : 'odd') . qq`"><td class="fname">$PREF{file_icon} <a href="$link" title="$tooltip">$displayname</a></td>`;
my $rawsize = my $size = -s "$PREF{uploaded_files_realpath}/$path$file";
my $numdec = $PREF{num_decimals_for_uploaded_files_list_sizes} =~ /^(\d+)$/ ? $1 : 0;
if($PREF{unit_for_size_display_in_uploaded_files_list} =~ /MB/i)
{
$size = sprintf("%.${numdec}f", $size /= 1024*1024);
$size .= ' $PREF{MB}';
}
elsif($PREF{unit_for_size_display_in_uploaded_files_list} =~ /KB/i)
{
$size = sprintf("%.${numdec}f", $size /= 1024);
$size .= " $PREF{KB}";
}
else
{
if($size >= 1024*1024)
{
$size = sprintf("%.${numdec}f", $size /= 1024*1024);
$size .= " $PREF{MB}";
}
else
{
$size = sprintf("%.${numdec}f", $size /= 1024);
$size .= " $PREF{KB}";
}
}
$size =~ s/^0 /1 / if $rawsize > 0; # for tiny files, round to 1 instead of 0.
print qq`<td class="size">$size</td>`;
my $fulldir = "$PREF{uploaded_files_realpath}/$path";
my $mtime = strftime($dateformat, localtime((stat("$fulldir$file"))[9] + $PREF{time_offset}));
my $ctime = strftime($dateformat, localtime((stat("$fulldir$file"))[10] + $PREF{time_offset}));
print qq`<td class="date">$mtime</td>`;
my $info_link = user_is_allowed_to('view_upload_info') && (($PREF{store_upload_info_in_files} =~ /yes/i && -e get_info_filename_withpath("$path$file")) || $PREF{store_upload_info_in_database} =~ /yes/i) ? qq`<a href="$PREF{here_filelist}?${userdir}action=fileinfo&path=$path_urlencoded&file=$file_urlencoded">info</a>` : '--';
print qq`<td class="info">$info_link</td>`;
print qq`<td class="mv"><a href="$PREF{here_filelist}?${userdir}action=move&file=$file_urlencoded&src=$path_urlencoded">mv</a></td>` if user_is_allowed_to('move_items') && $PREF{enable_subdirs} =~ /yes/i;
print qq`<td class="del"><a href="$PREF{here_filelist}?${userdir}action=delete&path=$path_urlencoded&file=$file_urlencoded">del</a></td>` if user_is_allowed_to('delete_items');
my ($path_for_js, $file_for_js) = ($path, $file);
s!'!\\'! for ($path_for_js, $file_for_js);
print qq`<td class="sel"><a href="javascript:select_item('$path_for_js$file_for_js')">$PREF{select_item_link}</a></td>` if user_is_allowed_to('order_items') && $PREF{enable_ordering} =~ /yes/i;
print qq`<td class="spc"></td>`;
print qq`</tr>\n`;
$i++;
}
print qq`\n</table>\n\n`;
print qq`<p>(Folder is empty)</p>\n` if ( ($PREF{enable_subdirs} =~ /yes/i && !@items) || ($PREF{enable_subdirs} !~ /yes/i && !@files) );
print_footer_links('home', 'uploader', 'mkdir', 'logout', 'login', 'selections', 'styleswitch', 'pb');
finish_html_output();
}
sub get_download_link
{
my ($path, $file, $path_urlencoded, $file_urlencoded) = @_;
if(!$file_urlencoded)
{
$file_urlencoded = $file;
enc_urlencode($file_urlencoded);
}
if(!$path_urlencoded)
{
$path_urlencoded = $path;
urlencode_path_but_leave_slashes($path_urlencoded);
}
my $link = ();
my $userdir = get_userdir_for_qs();
if($PREF{download_links_go_through_FileChucker} =~ /yes/i)
{
$link = "$ENV{SCRIPT_NAME}?${userdir}action=download&path=$path_urlencoded&file=$file_urlencoded";
}
elsif($PREF{download_links_go_through_PeerFactor} =~ /yes/i)
{
$link = "http://www.peerfactor.fr/get_myfile.jsp?URL=" . "$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{uploaded_files_urlpath}/$path$file";
}
else
{
$path .= '/' unless (!$path || $path =~ m!/$!);
#$link = "$PREF{uploaded_files_urlpath}/$path$file";
$link = "$PREF{uploaded_files_urlpath}/$path_urlencoded$file_urlencoded";
}
$link =~ s!/{2,}!/!g;
return $link;
}
sub urlencode_path_but_leave_slashes
{
foreach my $input_path (@_)
{
my @elements = split /[\/\\]+/, $input_path;
my $whole = ();
foreach my $element (@elements)
{
enc_urlencode($element);
$whole .= $element . '/';
}
$whole =~ s!/+$!! unless $input_path =~ m![/\\]$!;
$whole = '/' . $whole if $input_path =~ m!^[/\\]!;
$whole =~ s![/\\]+!/!g;
$input_path = $whole;
}
}
sub delete_old_files
{
return unless $PREF{automatically_delete_old_files} =~ /yes/i;
return unless ($PREF{old_file_ttl} =~ /^\d+(\.\d+)?$/ && $PREF{old_file_ttl} > 0);
my $current_hour = strftime("%H",localtime);
my $current_minute = strftime("%M",localtime);
for($current_hour, $current_minute)
{
s/^0// unless /^0$/; # because sftftime outputs leading zeros, but the user probably won't enter them that way.
}
my %hours_at_which_to_check = map { $_ => 1 } split(/[,\s]+/, $PREF{hours_at_which_to_check});
my %minutes_at_which_to_check = map { $_ => 1 } split(/[,\s]+/, $PREF{minutes_at_which_to_check});
if(($PREF{check_daily_for_old_files} =~ /yes/i && $hours_at_which_to_check{$current_hour}) || ($PREF{check_hourly_for_old_files} =~ /yes/i && $minutes_at_which_to_check{$current_minute}))
{
print STDERR "delete_old_files(): calling delete_files_and_folders_older_than($PREF{old_file_ttl})\n";
delete_files_and_folders_older_than($PREF{old_file_ttl});
}
}
sub info_system_is_enabled
{
return $PREF{store_upload_info_in_files} =~ /yes/i || $PREF{store_upload_info_in_database} =~ /yes/i;
}
sub print_server_headers
{
unless($PREF{output_started})
{
print "Cache-Control: no-store, no-cache\n";
print "Content-type: text/html\n\n";
$PREF{output_started} = 1;
}
}
sub print_js_and_css_headers
{
unless($PREF{output_started})
{
print "Content-type: text/plain\n\n";
$PREF{output_started} = 1;
}
}
sub start_html_output
{
my $title = shift;
my $css = shift;
my $js = shift;
$css = get_css() if $css;
$js = get_js() if $js;
print_server_headers();
if($PREF{print_full_html_tags} =~ /yes/i)
{
print qq`<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">`
. qq`\n<html xmlns="http://www.w3.org/1999/xhtml" lang="en" xml:lang="en">`
. qq`\n<head>`
. qq`\n<meta http-equiv="Content-type" content="text/html; charset=ISO-8859-1" />`
. qq`\n<title>$title</title>`
. qq`\n<script type="text/javascript">\n/* <![CDATA[ */ /* so (X)HTML validators ignore the javascript. */\n\n$js\n\n/* ]]> */ /* so (X)HTML validators ignore the javascript. */\n</script>`
. qq`\n<style type="text/css">$css</style>`
. qq`\n</head>`
. qq`\n<body id="fcbody">`
. qq`\n`;
}
else
{
print qq`$PREF{outer_container}\n`;
}
$PREF{perpage_container} =~ s!%%(\w+?)%%!$PREF{$1}!g;
print qq`$PREF{perpage_container}\n`; # this is #uploaderpage, #filelistpage, #defaultpage, etc.
print qq`$PREF{title}\n` if $PREF{title};
print qq`$PREF{inner_container}\n`;
}
sub finish_html_output
{
print qq`\n$PREF{inner_container_end}\n`; # end fc-container DIV.
print_powered_by() unless $PREF{hide_poweredby} =~ /yes/i;
print qq`\n$PREF{perpage_container_end}\n`; # end perpage_container DIV (#uploaderpage, #filelistpage, #defaultpage, etc).
if(($qs =~ /debug/) && ($PREF{enable_debug} =~ /yes/i))
{
my %perms = ();
my ($curdir) = ($ENV{SCRIPT_NAME} =~ m!^(.*)/!);
$perms{1}{item} = $ENV{SCRIPT_NAME};
$perms{1}{required} = '0755';
$perms{1}{actual} = sprintf "%04o", ((stat( "$PREF{DOCROOT}/$ENV{SCRIPT_NAME}" ))[2] & 07777);
$perms{2}{item} = $PREF{datadir};
$perms{2}{required} = '0777';
$perms{2}{actual} = sprintf "%04o", ((stat( "$PREF{datadir}" ))[2] & 07777);
$perms{3}{item} = $PREF{uploaded_files_realpath};
$perms{3}{required} = '0777';
$perms{3}{actual} = sprintf "%04o", ((stat( "$PREF{uploaded_files_realpath}" ))[2] & 07777);
print qq`\n\n<!-- debug:\n\n`;
foreach my $item (sort { $a <=> $b } keys %perms)
{
print qq`$perms{$item}{item}: required_mode=$perms{$item}{required}, actual_mode=$perms{$item}{actual}`;
print qq` (ERROR)` if $perms{$item}{required} ne $perms{$item}{actual};
print qq`\n`;
}
print qq`\$CGI::VERSION: $CGI::VERSION (v3.03 or better is STRONGLY recommended.)\n` #
. qq`\$] (Perl version): $]\n`
. qq`\$PREF{DOCROOT}: $PREF{DOCROOT}\n`
. qq`\$ENV{DOCUMENT_ROOT}: $ENV{DOCUMENT_ROOT}\n`
. qq`\$ENV{SCRIPT_FILENAME}: $ENV{SCRIPT_FILENAME}\n\n`
. qq`\$PREF{uploaded_files_dir}: $PREF{uploaded_files_dir}\n`
. qq`\$PREF{uploaded_files_realpath}: $PREF{uploaded_files_realpath}\n`
. qq`\$PREF{uploaded_files_urlpath}: $PREF{uploaded_files_urlpath}\n`
. qq`\n`;
foreach my $key (sort keys %PREF)
{
print qq`\n\$PREF{$key}: $PREF{$key}` unless ($key eq 'dbname' || $key eq 'dbuser' || $key eq 'dbpass');
}
print qq`\n\n`;
foreach my $key (sort keys %ENV)
{
print qq`\n\$ENV{$key}: $ENV{$key}`;
}
print qq`\n-->\n\n`;
}
if($PREF{print_full_html_tags} =~ /yes/i)
{
print qq`</body>\n</html>\n`;
}
else
{
print qq`$PREF{outer_container_end}\n`;
}
}
sub print_footer_links
{
my @links = ();
while(my $i = shift)
{
if($i =~ /uploader/) { push @links, qq`<a href="$PREF{here_uploader}` . get_qs_for_uploader_link() . qq`">Upload Files</a>` if user_is_allowed_to('upload'); }
elsif($i =~ /home/) { push @links, qq`<a href="$PREF{home_link_url}">$PREF{home_link_name}</a>`; }
elsif($i =~ /mkdir/) { if($PREF{enable_subdirs} =~ /yes/i) { push @links, qq`<a href="$PREF{here_filelist}?action=mkdir` . ($qs =~ /(?:^|&)path=(.+?)(?:&|$)/ ? "&path=$1" : undef) . ($PREF{keep_userdir_on_url} =~ /yes/i ? "&userdir=" . get_userdir() : undef) . qq`">New Folder</a>` if user_is_allowed_to('make_folder_thru_fileman'); } }
elsif($i =~ /selections/) { push @links, qq`<a href="$PREF{here_filelist}?action=view_items` . ($PREF{keep_userdir_on_url} =~ /yes/i ? '&' . get_userdir_for_qs() : undef) . qq`">$PREF{view_items_page_name}</a>` if user_is_allowed_to('order_items') && $PREF{enable_ordering} =~ /yes/i; }
elsif($i =~ /pb/) { push @links, print_pb_short(); }
elsif($i =~ /logout/) { my $go = get_logout_url(); push (@links, qq`<a href="$go">Logout</a>`) if $PREF{member_is_logged_in}; }
elsif($i =~ /login/) { my $go = get_login_url(); push (@links, qq`<a href="$go">Login</a>`) if (login_features_enabled() && !$PREF{member_is_logged_in} && $PREF{show_login_link} =~ /yes/i); }
elsif($i =~ /list/) { push (@links, qq`<a href="$PREF{here_filelist}?action=listfiles` . ($PREF{keep_userdir_on_url} =~ /yes/i ? "&userdir=" . get_userdir() : undef) . qq`">Show Uploads</a>`) if show_link_to_uploads(); }
elsif($i =~ /getscript/) { push (@links, qq`<a href="http://encodable.com/filechucker/" target="_blank">Get This Script</a>`); }
elsif($i =~ /styleswitch/) { push (@links, get_style_switcher_links()) if ($PREF{enable_filelist_style_switcher_link} =~ /yes/i); }
}
if($PREF{on_page} eq 'uploader' && exists $PREF{custom_footer_for_uploader}) { print $PREF{custom_footer_for_uploader}; }
elsif($PREF{on_page} eq 'uploadcomplete' && exists $PREF{custom_footer_for_uploadcomplete_page}) { print $PREF{custom_footer_for_uploadcomplete_page}; }
elsif($PREF{on_page} eq 'filelist' && exists $PREF{custom_footer_for_filelist}) { print $PREF{custom_footer_for_filelist}; }
elsif($PREF{on_page} eq 'default' && exists $PREF{custom_footer_for_default_pages}) { print $PREF{custom_footer_for_default_pages}; }
else { print qq`$PREF{footer_markup_start}\n`; print join " – ", @links; print qq`$PREF{footer_markup_end}\n`; }
}
sub print_powered_by
{
print qq`<div id="pb">\n`;
print get_powered_by();
print qq`</div>\n`;
}
sub get_powered_by
{
return qq`<a href="http://encodable.com/filechucker/" target="_blank">Powered by Encodable</a>`;
}
sub print_pb_short
{
return qq`<a href="http://encodable.com/filechucker/" target="_blank">Encodable</a>`;
}
sub get_logout_url
{
return $PREF{integrate_with_UserBase} =~ /yes/i || $PREF{integrate_with_existing_login_system} =~ /yes/i ? $PREF{logout_url} : "$ENV{SCRIPT_NAME}?logout";
}
sub get_login_url
{
return $PREF{integrate_with_UserBase} =~ /yes/i || $PREF{integrate_with_existing_login_system} =~ /yes/i ? $PREF{login_url} : "$PREF{here_login}?login";
}
sub get_qs_for_uploader_link
{
my @items = ();
my $qs_for_uploader_link = ();
if($PREF{default_page} ne 'uploader')
{
push @items, 'action=upload';
}
if($PREF{enable_userdirs} =~ /yes/i && $PREF{keep_userdir_on_url} =~ /yes/i)
{
push @items, "userdir=" . get_userdir();
}
if(@items)
{
for(@items)
{
$qs_for_uploader_link .= $_ . '&';
}
$qs_for_uploader_link =~ s/&$//;
$qs_for_uploader_link = "?$qs_for_uploader_link";
}
return $qs_for_uploader_link;
}
sub get_style_switcher_links
{
my $links = 'Style: ';
foreach my $style (split(/[, ]+/, $PREF{enabled_styles}))
{
if(get_current_filelist_style() eq $style)
{
$links .= $style . ' ';
}
else
{
$links .= qq`<a href="javascript:set_cookie('fcliststyle', '$style', 365*24, '/'); location.reload()">$style</a> `;
}
}
return $links;
}
# vlog, fc
sub make_password_hash
{
if($ENV{REQUEST_METHOD} =~ /post/i)
{
use Digest::MD5 'md5_hex';
use CGI ':param';
my $hashed_password = md5_hex(param('password'));
start_html_output('Here is your hashed password...', 'css', 'js');
print qq`<div>The hashed version of the password you just entered is:<br /><br />$hashed_password</div>`
. qq`\n`;
print_footer_links('home', 'uploader', 'login');
finish_html_output();
}
else
{
start_html_output('Enter your new password', 'css', 'js');
print qq`<form method="post" action="$ENV{SCRIPT_NAME}?makePasswordHash">`
. qq`\nEnter your new password:`
. qq`\n<br /><br /><input type="password" name="password" maxlength="200" />`
. qq`\n<br /><br /><input type="submit" value="create hash" />`
. qq`\n</form>`
. qq`\n`;
print_footer_links('home', 'uploader', 'login');
finish_html_output();
}
}
sub user_is_allowed_to
{
my $target = shift;
if(!login_features_enabled())
{
return 1;
}
elsif($PREF{"must_be_admin_to_$target"} =~ /yes/i)
{
return $PREF{admin_is_logged_in};
}
elsif($PREF{"must_be_member_to_$target"} =~ /yes/i)
{
return $PREF{member_is_logged_in};
}
else
{
return 1;
}
}
sub print_needlogin_error_and_exit
{
my $target = shift;
my $login_url = $PREF{integrate_with_UserBase} =~ /yes/i || $PREF{integrate_with_existing_login_system} =~ /yes/i ? $PREF{login_url} : "$PREF{here_login}?action=login&target=$target";
start_html_output('Authentication Required', 'css', 'js');
print qq`<h1>Authentication Required</h1>`
. qq`\n<div style="margin: 30px;">You must <a href="$login_url">log in</a> first.</div>`
. qq`\n`;
#print_footer_links('home','list') unless ($PREF{must_be_member_to_list_files} =~ /yes/i || $PREF{must_be_admin_to_list_files} =~ /yes/i);
print_footer_links('home', 'uploader', 'list');
finish_html_output();
exit;
}
sub exit_with_message
{
my $title = shift;
my $msg = shift;
start_html_output($title, 'css', 'js');
print qq`<h2>$title</h2>`
. qq`\n<div>$msg<br /><br /></div>`
. qq`\n`;
print_footer_links('home');
finish_html_output();
exit;
}
sub do_login
{
my $target = shift;
if($ENV{REQUEST_METHOD} =~ /post/i)
{
use Digest::MD5 'md5_hex';
use CGI ':param';
if(param('password') !~ /\S/) # don't allow blank passwords.
{
start_html_output('Error', 'css');
print qq`<div>You must enter the password.</div>`;
finish_html_output();
exit;
}
my $hashed_password = md5_hex(param('password'));
my $expiry = ();
if(param('persist') eq 'on')
{
$expiry = "+$PREF{num_days_login_lasts}d";
}
if($hashed_password eq $PREF{admin_password_hash} || $hashed_password eq $PREF{member_password_hash})
{
set_cookie('enc-uploader-password', $hashed_password, $expiry);
if($target eq 'list_files')
{
if($ENV{SERVER_SOFTWARE} =~ /microsoft-iis/i)
{
# A bug in IIS v5 (and lower, probably) makes cookie-setting fail
# when combined with a header-based redirect:
#
# "BUG: Set-Cookie Is Ignored in CGI When Combined With Location"
# http://support.microsoft.com/kb/q176113/
#
# So use a meta-redirect instead.
#
print "Content-type: text/html\n\n";
print qq`<html><head><meta http-equiv="refresh" content="0;url=$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_filelist}?action=listfiles"></head><body></body></html>\n`;
}
else
{
print "Location: $PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_filelist}?action=listfiles\n\n";
}
}
else # default to the front page (the upload page).
{
if($ENV{SERVER_SOFTWARE} =~ /microsoft-iis/i)
{
print "Content-type: text/html\n\n";
print qq`<html><head><meta http-equiv="refresh" content="0;url=$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_uploader}"></head><body></body></html>\n`;
}
else
{
print "Location: $PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_uploader}\n\n";
}
}
}
else
{
start_html_output('Invalid Login', 'css');
print qq`<div>The password you entered is incorrect.<br />Go back and try again.</div>`
. qq`\n`;
finish_html_output();
}
}
else
{
my $scripttarget = $target ? "action=login&target=$target" : 'login';
start_html_output('Enter the password', 'css');
print qq`<form method="post" action="$ENV{SCRIPT_NAME}?$scripttarget">`
. qq`\nEnter the password:`
. qq`\n<br /><br /><input type="password" name="password" maxlength="200" />`
. qq`\n<br /><br /><input type="checkbox" name="persist" /> Keep me logged in for $PREF{num_days_login_lasts} days`
. qq`\n<br /><br /><input type="submit" value="log in" />`
. qq`\n</form>`
. qq`\n`;
finish_html_output();
}
}
sub login_features_enabled
{
if(
(
action_restrictions_enabled()
)
&&
(
$PREF{member_password_hash} =~ /\S/
||
$PREF{admin_password_hash} =~ /\S/
||
$PREF{integrate_with_UserBase} =~ /yes/i
||
$PREF{integrate_with_existing_login_system} =~ /yes/i
)
)
{
return 1;
}
}
sub action_restrictions_enabled
{
foreach my $pref (keys %PREF)
{
if($pref =~ /^must_be_(member|admin)_to_/)
{
if($PREF{$pref} =~ /yes/i)
{
return 1;
}
}
}
return 0;
}
sub show_files_as_links_on_upload_complete_page
{
return (
$PREF{upload_complete_page_links_to_files_for_strangers} =~ /yes/i
||
($PREF{upload_complete_page_links_to_files_for_members} =~ /yes/i && $PREF{member_is_logged_in})
||
($PREF{upload_complete_page_links_to_files_for_admins} =~ /yes/i && $PREF{admin_is_logged_in})
);
}
sub do_logout()
{
set_cookie('enc-uploader-password', 'blank', '-1d');
# Remove the "logout" from the referrer, otherwise we'll get stuck
# in an infinite logout loop with this Location: call.
$ENV{HTTP_REFERER} =~ s/\?logout$//;
#my $go = $ENV{HTTP_REFERER} ? $ENV{HTTP_REFERER} : "$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_login}";
my $go = "$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_login}?action=loggedout&whence=$ENV{HTTP_REFERER}";
if($ENV{SERVER_SOFTWARE} =~ /microsoft-iis/i)
{
print "Content-type: text/html\n\n";
print qq`<html><head><meta http-equiv="refresh" content="0;url=$go"></head><body></body></html>\n`;
}
else
{
print "Location: $go\n\n";
}
}
sub make_dir
{
my $path = shift;
my $dirname = shift;
unless(user_is_allowed_to('make_folder_thru_fileman'))
{
#print_not_allowed_error_and_exit();
print_needlogin_error_and_exit();
}
enc_urldecode($path, $dirname);
$path = enc_untaint($path, 'keep_path') if $path;
$dirname = enc_untaint($dirname) if $dirname;
clean_up_filename($dirname) if $PREF{clean_up_filenames} =~ /yes/i;
remove_reserved_strings($dirname);
if($path && $dirname)
{
my $num_subdir_levels = 0;
my $testpath = "/$path";
while($testpath =~ m!(/|\\)[^/\\]+!g)
{
$num_subdir_levels++;
}
if( ($PREF{max_num_of_subdir_levels} !~ /^\d+$/) || ($num_subdir_levels < $PREF{max_num_of_subdir_levels}) )
{
my $maxlen = $PREF{max_length_of_new_subdir_names};
$dirname =~ s/^(.{1,$maxlen}).*/$1/;
my $fullpath_url = $PREF{hide_path_to_uploads_dir} =~ /yes/i ? "/$path/$dirname" : $PREF{uploaded_files_urlpath} . "/$path/$dirname";
my $fullpath_real = $PREF{uploaded_files_realpath} . "/$path/$dirname";
my $path_urlencoded = "$path/$dirname";
s![/\\]{2,}!/!g for ($fullpath_url, $fullpath_real, $path_urlencoded);
enc_urlencode($path_urlencoded);
if(mkdir($fullpath_real,0777) && chmod(0777,$fullpath_real))
{
my $userdir = get_userdir_for_qs();
start_html_output('Creating...', 'css');
print qq`<h3>New Folder Created Successfully:</h3>`
. qq`\n<p><a href="$PREF{here_filelist}?action=listfiles&${userdir}path=$path_urlencoded">$fullpath_url</a></p>`
. qq`\n`;
print_footer_links('home','uploader','list');
finish_html_output();
}
else
{
die_nice(qq`Error: couldn't create directory "$fullpath_url": $!`);
}
}
else
{
die_nice(qq`Error: couldn't create directory: sublevel limit ($num_subdir_levels) would be exceeded.`);
}
}
else
{
my $hidden_userdir_input = $PREF{enable_userdir_on_url} =~ /yes/i && $PREF{keep_userdir_on_url} =~ /yes/i ? qq`<input type="hidden" name="userdir" value="` . (get_userdir()) . qq`" />` : undef;
start_html_output('Make New Directory', 'css');
print qq`<h2>Make New Directory</h2>\n<br /><h3>Location:</h3>`
. qq`\n<form method="get" action="$PREF{here_filelist}">`
. qq`\n` . $hidden_userdir_input
. qq`\n<br /><input type="hidden" name="action" value="mkdir" />`
. qq`\n<select name="path">`
;
print qq`\n<option value="/">` . (get_uploaded_files_url_path('without_trailing_slash')) . qq`/</option>`;
foreach my $dir (sort { lc($a) cmp lc($b) } (get_all_subdirs($PREF{uploaded_files_realpath})))
{
print qq`\n<option value="$dir"` . ($dir eq "$path" ? qq` selected="selected"` : undef) . qq`>` . (get_uploaded_files_url_path('without_trailing_slash')) . qq`/$dir/</option>`;
}
print qq`\n</select>`
. qq`\n<br /><br /><h3>Name:</h3>`
. qq`\n<br /><input type="text" name="dirname" class="default" />`
. qq`\n<br /><br /><br /><input type="submit" value="Create It" class="defaultbutton" />`
. qq`\n</form>`
. qq`\n`;
print_footer_links('home','uploader','list');
finish_html_output();
}
}
sub delete_item
{
my $path = shift;
my $itemtype = shift;
my $name = shift;
my $really = shift;
unless(user_is_allowed_to('delete_items'))
{
#print_not_allowed_error_and_exit();
print_needlogin_error_and_exit();
}
enc_urldecode($path, $name);
my $displayname = $name;
enc_urldecode($displayname);
if($displayname =~ /(\d{15,})(\..{1,6})$/)
{
my ($to_replace,$end) = ($1,$2);
my ($replacement) = ($to_replace =~ /^(\d{12})/);
$displayname =~ s/$to_replace$end/$replacement...$end/;
}
my $name_decoded = $name;
enc_urldecode($name_decoded);
my $diskitem = "$PREF{uploaded_files_realpath}/$path/$name_decoded";
my $siteitem = "$PREF{uploaded_files_urlpath}/$path/$name_decoded";
s![/\\]{2,}!/!g for ($diskitem, $siteitem);
if($really)
{
my $new_qs = get_path_and_userdir_for_qs();
# We can't do a print:Location... here because we're likely running under
# an SSI/PHP include, which means headers have already been sent. So do
# a meta-refresh instead.
#
my $redirect_after_deletion = "Content-type: text/html\n\n"
. qq`<html><head><meta http-equiv="refresh" content="0;url=$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_filelist}?action=listfiles` . ($new_qs ? "&$new_qs" : undef) . qq`"></head><body></body></html>\n`;
if($itemtype eq 'file')
{
unlink($diskitem) or die "$0: couldn't delete \"$diskitem\": $!\n";
my $infofile_error = ();
my ($file_with_urlpath) = ($diskitem =~ /^$PREF{DOCROOT}(.+$)/);
if(-e (my $infofile = get_info_filename_withpath($file_with_urlpath)) )
{
#print STDERR "deleting $infofile\n";
unlink($infofile) or $infofile_error = qq`$0: couldn't unlink (delete) infofile "$infofile": $!\n`;
}
if($infofile_error)
{
start_html_output('Deleting...', 'css');
print qq`<h3>File deleted successfully:</h3>`
. qq`\n<div>$displayname</div>`
. qq`\n`;
print qq`<p><br /><br />However, there was a problem removing the infofile:</p>\n<p>$infofile_error</p>\n\n`;
print_footer_links('home','uploader','list');
finish_html_output();
}
else
{
print $redirect_after_deletion;
}
}
else
{
my $infofile_errors = delete_directory($diskitem);
if(@$infofile_errors)
{
start_html_output('Deleting...', 'css');
print qq`<h3>Directory deleted successfully:</h3>`
. qq`\n<div>$siteitem</div>`
. qq`\n`;
print qq`<p><br /><br />However, there were problems deleting the infofile(s):</p>`
. qq`\n<p>`
. join "\n</p><p>", @$infofile_errors
. qq`\n</p>`;
print_footer_links('home','uploader','list');
finish_html_output();
}
else
{
print $redirect_after_deletion;
}
}
}
else
{
start_html_output('Confirm deletion', 'css');
if($itemtype eq 'file')
{
print qq`<h3>Really delete this file?</h3>`
. qq`\n<p><a href="$siteitem" target="_blank">$displayname</a></p>`
. qq`\n`;
}
else
{
print qq`<h3>Really delete this directory?</h3>\n`
. qq`\n<p>$siteitem</p>`
. qq`\n`;
my ($filecount, $dircount) = count_items($diskitem);
if($filecount || $dircount)
{
print qq`\n<p>This directory contains $filecount file(s) and $dircount folder(s). `
. qq`\nIf you delete it, they will all be deleted too. Are you sure you want `
. qq`\nto delete this directory and all its contents?</p>`
. qq`\n`;
}
}
print qq`\n<div><br />[<a href="$PREF{here_filelist}?$qs&really=yes">Yes</a>] `
. qq`\n[<a href="$PREF{here_filelist}?` . get_userdir_for_qs() . qq`action=listfiles">No</a>]<br /><br /></div>`
. qq`\n`;
print_footer_links('home','uploader','list');
finish_html_output();
}
}
sub move_item
{
my $action = shift;
my $itemtype = shift;
my $item = shift;
my $src = shift;
my $dst = shift;
unless(user_is_allowed_to('move_items'))
{
#print_not_allowed_error_and_exit();
print_needlogin_error_and_exit();
}
enc_urldecode($item, $src, $dst);
$item = enc_untaint($item);
$src = enc_untaint($src, 'keep_path') if $src;
if($action eq 'move')
{
$dst = enc_untaint($dst, 'keep_path') if $dst;
}
else # rename, so $dst is a filename with no path.
{
$dst = enc_untaint($dst) if $dst;
clean_up_filename($dst) if $PREF{clean_up_filenames} =~ /yes/i;
remove_reserved_strings($dst);
}
# Note: here "local" means just like "url" except without $PREF{uploaded_files_urlpath} on the front.
my ($localsrc, $localdst, $urlsrc, $urldst, $fullsrc, $fulldst, $fullitem_src, $fullitem_dst, $urlitem_src, $urlitem_dst, $localitem_src, $localitem_dst) = ();
$localsrc = '/' . $src;
$urlsrc = $PREF{uploaded_files_urlpath} . $localsrc;
$urlitem_src = $PREF{uploaded_files_urlpath} . $localsrc . '/' . $item;
$fullsrc = $PREF{uploaded_files_realpath} . $localsrc;
$fullitem_src = $PREF{uploaded_files_realpath} . $localsrc . '/' . $item;
$localitem_src = $localsrc . '/' . $item;
if($action eq 'move')
{
$localdst = '/' . $dst;
$urldst = $PREF{uploaded_files_urlpath} . $localdst;
$urlitem_dst = $PREF{uploaded_files_urlpath} . $localdst . '/' . $item;
$fulldst = $PREF{uploaded_files_realpath} . $localdst;
$fullitem_dst = $PREF{uploaded_files_realpath} . $localdst . '/' . $item;
$localitem_dst = $localdst . '/' . $item;
}
else # rename. here, $dst is just a filename or foldername with no path (and the "src=" on the URL was null) -- the path for dst is the same as the src path.
{
$localdst = '/';
$urldst = $urlsrc;
$urlitem_dst = $urlsrc . $localdst . $dst;
$fulldst = $fullsrc;
$fullitem_dst = $fullsrc . $localdst . $dst;
$localitem_dst = $localdst . $dst;
}
s![/\\]{2,}!/!g for ($localsrc, $localdst, $urlsrc, $urldst, $fullsrc, $fulldst, $fullitem_src, $fullitem_dst, $urlitem_src, $urlitem_dst);
if($dst)
{
if(! -e $fullitem_src)
{
die_nice(qq`Error: can't find $itemtype $item in $urlsrc.`);
}
elsif($action eq 'rename' && -f $fullitem_src && ! -d $fullitem_src && $dst !~ /.+\..+/ && $PREF{allow_files_without_extensions} !~ /yes/i)
{
# If the source is a normal file (not a directory) and the destination
# filename doesn't have an extension, but they've enabled the extension
# filters, then it's an error.
die_nice(qq`Error: destination filename ("$dst") appears to have no extension.`);
}
elsif(-e $fullitem_dst)
{
die_nice(qq`Error: there is already a $itemtype named $item in $urldst. If you really want to overwrite it you must delete the existing $itemtype first.`);
}
else
{
my ($title, $output, $errormsg) = ();
if($action eq 'move')
{
$title = 'Moving...';
$output = qq`<h3>Moved $itemtype:</h3>\n<p>$item</p>`
. qq`<h3>From:</h3>\n<p>$urlsrc</p>`
. qq`<h3>To:</h3>\n<p><a href="$PREF{here_filelist}?` . (get_userdir_for_qs()) . qq`action=listfiles&path=` . (enc_urlencode($dst) || 1 ? $dst : undef) . qq`">$urldst</a></p>`
. qq`\n`
. qq`\n`;
$errormsg = qq`Error while trying to move $itemtype "$item" from $urlsrc to $urldst: $!`;
}
else
{
$title = 'Renaming...';
$output = qq`<h3>Renamed $itemtype:</h3>\n<p>$item</p>`
. qq`<h3>To:</h3>\n<p>$dst</p>`
. qq`<h3>In:</h3>\n<p><a href="$PREF{here_filelist}?` . (get_userdir_for_qs()) . qq`action=listfiles&path=` . (enc_urlencode($src) || 1 ? $src : undef) . qq`">$urlsrc</a></p>`
. qq`\n`
. qq`\n`;
$errormsg = qq`Error while trying to rename $itemtype "$item" to "$dst" in $urlsrc: $!`;
}
my ($files_for_infofiles, undef) = get_items($fullitem_src) if($itemtype eq 'folder');
if(rename($fullitem_src, $fullitem_dst))
{
my @infofile_errors = ();
if($itemtype eq 'folder')
{
my $errors = move_all_infofiles($files_for_infofiles, $urlitem_src, $urlitem_dst);
@infofile_errors = @$errors if @$errors;
}
else
{
if(-e (my $old_infofile = get_info_filename_withpath($localitem_src)) )
{
my $new_infofile = get_info_filename_withpath($localitem_dst);
rename($old_infofile, $new_infofile) or push @infofile_errors, qq`couldn't move infofile from "$old_infofile" to "$new_infofile": $!`;
}
if($PREF{store_upload_info_in_database} =~ /yes/i)
{
slashify(my $oldpath = $localsrc);
slashify(my $newpath = $localdst);
my $oldfilename = $item;
my $newfilename = $action eq 'move' ? $item : $dst;
my $sth = $dbh->prepare(qq`UPDATE $PREF{db_table_for_upload_info} SET filepath='$newpath',filename='$newfilename' WHERE filepath='$oldpath' AND filename='$oldfilename' LIMIT 1;`);
my $success = $sth->execute();
if(!$success || $success =~ /^(0|0E0)$/)
{
push(@infofile_errors, qq`couldn't update filepath (from '$oldpath' to '$newpath') and/or filename (from '$oldfilename' to '$newfilename') in upload info database: $DBI::errstr`);
#print STDERR "infofile_errors[0]=$infofile_errors[0]\n";
}
}
}
start_html_output($title, 'css');
print $output;
if(@infofile_errors)
{
print qq`<p><br /><br />However, there were problems moving the infofile(s):</p>`
. qq`\n<p>`
. join("\n</p><p>", @infofile_errors)
. qq`\n</p>`;
}
print_footer_links('home','uploader','list');
finish_html_output();
}
else
{
die_nice($errormsg);
}
}
}
else
{
my $hidden_userdir_input = $PREF{enable_userdir_on_url} =~ /yes/i && $PREF{keep_userdir_on_url} =~ /yes/i ? qq`<input type="hidden" name="userdir" value="` . (get_userdir()) . qq`" />` : undef;
start_html_output("Move/Rename $itemtype", 'css');
print qq`<h3>Move $itemtype:</h3>\n<p>$item</p>`
. qq`\n<h3>From:</h3>\n<p>$urlsrc</p>`
. qq`\n<h3>To:</h3>`
. qq`\n<form method="get" action="$PREF{here_filelist}">`
. qq`\n` . $hidden_userdir_input
. qq`\n<input type="hidden" name="action" value="move" />`
. qq`\n<input type="hidden" name="$itemtype" value="$item" />`
. qq`\n<input type="hidden" name="src" value="$src" />`
. qq`\n<select name="dst">`
;
print qq`\n<option value="/">` . (get_uploaded_files_url_path('without_trailing_slash')) . qq`/</option>`;
foreach my $dir (sort { lc($a) cmp lc($b) } (get_all_subdirs($PREF{uploaded_files_realpath})))
{
print qq`\n<option value="$dir">` . (get_uploaded_files_url_path('without_trailing_slash')) . qq`/$dir/</option>`;
}
print qq`\n</select>`
. qq`\n<br /><br /><input type="submit" value="Move It" class="defaultbutton" />`
. qq`\n</form>`
. qq`\n`;
print qq`\n<div class="hr"></div>`
. qq`\n<h1>Or:</h1>`
. qq`\n<div class="hr"></div>`
. qq`\n<h3>Rename $itemtype:</h3>\n<p>$item</p>`
. qq`\n<h3>To:</h3>`
. qq`\n<form method="get" action="$PREF{here_filelist}">`
. qq`\n` . $hidden_userdir_input
. qq`\n<input type="hidden" name="action" value="rename" />`
. qq`\n<input type="hidden" name="$itemtype" value="$item" />`
. qq`\n<input type="hidden" name="src" value="$src" />`
. qq`\n<input type="text" name="dst" value="$item" class="default" />`
. qq`\n<br /><br /><input type="submit" value="Rename It" class="defaultbutton" />`
. qq`\n<br /><br /></form>`
. qq`\n`;
print_footer_links('home','uploader','list');
finish_html_output();
}
}
sub slashify
{
# add leading and trailing slashes and condense duplicates.
$_ = '/' . $_ . '/' for @_;
s!/{2,}!/!g for @_;
}
sub view_items
{
my $selections = get_cookie($PREF{selection_cookie_name});
my $i = 1;
my @items = split(/:\|:\|:/, $selections);
start_html_output($PREF{view_items_page_name}, 'css', 'js');
print $PREF{view_items_page_intro} . "\n";
print qq`<table id="selections_table">\n`;
foreach my $item (sort @items)
{
my ($path, $file) = split(/\//, $item);
unless($file) { $file = $path; $path = (); }
print qq`<tr class=` . ($i % 2 == 0 ? 'even' : 'odd') . qq`><td>$i: <a href="` . get_download_link($path, $file) . qq`">$item</td></tr>\n`;
$i++;
}
print qq`</table>\n`;
print qq`<p style="font-style: italic;">(No items)</p>\n` unless $selections;
if($selections)
{
print qq`<div id="place_order">`
. qq`\n<form id="theorderform" method="get" action="$ENV{SCRIPT_NAME}">`
. qq`\n<input type="hidden" name="action" value="process_order" />`
. ($PREF{enable_userdirs} =~ /yes/i && $PREF{enable_userdir_on_url} =~ /yes/i ? qq`\n<input type="hidden" name="userdir" value=` . get_userdir() . qq`" />` : undef)
. qq`\n` . $PREF{place_order_fields}
. qq`\n</form>`
. qq`\n</div>`
. qq`\n`;
print qq`<p><a href="javascript:clear_selections()">$PREF{clear_selections_text}</a></p>\n`;
}
print_footer_links('home','uploader','list');
finish_html_output();
}
sub process_order
{
my $selections = get_cookie($PREF{selection_cookie_name});
die_nice(qq`Error: your cart is empty.`) unless $selections;
my @items = split(/:\|:\|:/, $selections);
my $user_info = ();
my $user_email = ();
for(split(/&/, $qs))
{
my ($name, $value) = split(/=/);
next if $name eq 'action';
enc_urldecode($name);
enc_urldecode($value);
$user_info .= qq`<p><b>$name</b>: $value</p>\n`;
$user_email = $value if ($name =~ /e-?mail/i);
}
my $email_message = qq`<html>\n<body style="font-family: sans-serif;">`
. qq`\n$PREF{order_email_top_intro}`
. qq`\n$PREF{order_email_user_intro}`
. qq`\n$user_info`
. qq`\n$PREF{order_email_items_intro}`
. qq`\n<table style="border: 1px solid #999; border-collapse: collapse;">\n`
. qq`\n`;
my $i = 1;
foreach my $item (sort @items)
{
my ($path, $file) = split(/\//, $item);
unless($file) { $file = $path; $path = (); }
my $link = get_download_link($path, $file);
$link = "$PREF{protoprefix}$ENV{HTTP_HOST}$link" unless $link =~ m!^https?://!;
$email_message .= qq`<tr style="background: ` . ($i % 2 == 0 ? '#fff' : '#efefef') . qq`;"><td style="padding: 4px;">$i: <a href="$link">$item</td></tr>\n`;
$i++;
}
$email_message .= qq`</table>\n</body>\n</html>\n`;
# send the email.
my @recipients = ();
foreach my $pref (sort keys %PREF)
{
if($pref =~ /^order_email_recipient_\d+$/)
{
push @recipients, $PREF{$pref};
}
}
push (@recipients, $user_email) if $PREF{send_copy_to_userEntered_email_address} =~ /yes/i;
for(@recipients)
{
die_nice(qq`Error: cannot continue because this email address is invalid: "$_".`) unless /.+\@.+\..+/;
}
for(@recipients)
{
send_email($_, $PREF{order_sender_email_address}, $PREF{order_email_subject}, $email_message, 'text/html', 'die_on_email_error');
}
# clear the user's cart and redirect to the confirmation page.
set_cookie($PREF{selection_cookie_name}, undef);
my $go = "$PREF{protoprefix}$ENV{HTTP_HOST}$PREF{here_filelist}?" . ($PREF{keep_userdir_on_url} ? get_userdir_for_qs() : undef) . "action=order_confirmation&items=$selections";
if($ENV{SERVER_SOFTWARE} =~ /microsoft-iis/i)
{
# A bug in IIS v5 (and lower, probably) makes cookie-setting fail
# when combined with a header-based redirect:
#
# "BUG: Set-Cookie Is Ignored in CGI When Combined With Location"
# http://support.microsoft.com/kb/q176113/
#
# So use a meta-redirect instead.
#
print "Content-type: text/html\n\n";
print qq`<html><head><meta http-equiv="refresh" content="0;url=$go"></head><body></body></html>\n`;
}
else
{
print "Location: $go\n\n";
}
}
sub order_confirmation
{
my @items = ();
if($qs =~ /(?:^|&)items=(.+?)(?:&|$)/)
{
my $selections = $1;
enc_urldecode($selections);
@items = split(/:\|:\|:/, $selections);
}
start_html_output($PREF{process_order_page_name}, 'css', 'js');
print $PREF{process_order_page_intro} . "\n";
if(@items)
{
print qq`<table id="selections_table">\n`;
my $i = 1;
foreach my $item (sort @items)
{
my ($path, $file) = split(/\//, $item);
unless($file) { $file = $path; $path = (); }
print qq`<tr class=` . ($i % 2 == 0 ? 'even' : 'odd') . qq`><td>$i: <a href="` . get_download_link($path, $file) . qq`">$item</td></tr>\n`;
$i++;
}
print qq`</table>\n`;
}
print_footer_links('home','uploader','list');
finish_html_output();
}
sub die_nice
{
my $msg = shift;
$msg =~ s![\r\n]+!\n<br />!g;
start_html_output('Error', 'css');
print qq`<div>$msg</div>\n`;
print_footer_links('home','uploader','list');
finish_html_output();
exit;
}
sub printd
{
if($PREF{debug})
{
print STDERR "filechucker-debug: " . (time + $PREF{time_offset}) . ": " . $_[0] . "\n";
print_server_headers();
print "<!-- filechucker-debug: " . (time + $PREF{time_offset}) . ": " . $_[0] . " -->\n";
}
}
sub get_db_connection
{
my $dbh = DBI->connect("dbi:mysql:$PREF{dbname}", $PREF{dbuser}, $PREF{dbpass}, {AutoCommit => 1} )
or die "$0: $DBI::errstr\n";
if(!db_table_exists($dbh) || !db_table_is_right_size($dbh))
{
create_db_table_for_temp_data($dbh);
}
$PREF{AutoCommit} = $dbh->{AutoCommit};
return $dbh;
}
sub create_db_table_for_temp_data
{
my $dbh = shift;
my $statement = qq`CREATE TABLE $PREF{table_name_for_temp_data} `
. qq`(serial VARCHAR(150) NOT NULL PRIMARY KEY, `
. qq`progress TEXT, `
. qq`currentfile SMALLINT, `
. qq`totalfiles SMALLINT, `
. qq`totalsize INT UNSIGNED, `
. qq`start_time INT UNSIGNED); `;
my $sth = $dbh->prepare($statement);
$sth->execute or die "$0: couldn't create new database table $PREF{table_name_for_temp_data}: $DBI::errstr\n";
}
sub db_table_exists
{
my $dbh = shift;
my @alltables = $dbh->tables();
die "$0: couldn't get table names\n" unless @alltables;
my $exists = 0;
foreach my $table (@alltables)
{
$table =~ s/[\`'"]//g; # because $dbh->tables() returns the table-names quoted with backticks.
if($table eq $PREF{table_name_for_temp_data})
{
$exists = 1;
last;
}
}
return $exists;
}
sub db_table_is_right_size
{
my $dbh = shift;
my $sth = $dbh->prepare("SHOW COLUMNS FROM $PREF{table_name_for_temp_data};");
$sth->execute();
my @row = $sth->fetchrow;
return (scalar(@row) == 6);
}
sub get_ip_and_host
{
my $ip = $ENV{REMOTE_ADDR};
my $host = $ENV{REMOTE_HOST};
if(!($host)) { $host = $ip; }
if($host eq $ip)
{
use Socket;
$host = gethostbyaddr(inet_aton($ip), AF_INET);
}
if(!($host)) { $host = $ip; }
return ($ip, $host);
}
sub delete_directory
{
my $dir = shift;
my ($files, $subfolders) = get_items($dir);
my @infofile_errors = ();
# first delete the files.
#
foreach my $file (@$files)
{
$file = enc_untaint($file, 'keep_path');
# can never be too safe...
if($file =~ /^\Q$PREF{uploaded_files_realpath}\E/)
{
if($PREF{uploaded_files_realpath} =~ /^\Q$PREF{DOCROOT}\E/)
{
#print STDERR "unlinking $file\n";
unlink($file) or die qq`$0: couldn't unlink (delete) file "$file": $!\n`;
my ($file_with_urlpath) = ($file =~ /^\Q$PREF{DOCROOT}\E(.+$)/);
if(-e (my $infofile = get_info_filename_withpath($file_with_urlpath)) )
{
#print STDERR "deleting $infofile\n";
unlink($infofile) or push @infofile_errors, qq`$0: couldn't unlink (delete) infofile "$infofile": $!\n`;
}
}
else
{
die qq`$0: refusing to unlink "$file" because \$PREF{uploaded_files_realpath} ($PREF{uploaded_files_realpath}) does not appear to be within \$PREF{DOCROOT} ($PREF{DOCROOT}).\n`;
}
}
else
{
die qq`$0: refusing to unlink "$file" because it doesn't appear to be within \$PREF{uploaded_files_realpath} ($PREF{uploaded_files_realpath}).\n`;
}
}
# next delete the folders.
# start with the longest pathname to ensure we delete subdirectories before parent directories.
#
foreach my $folder (sort { length($b) <=> length($a) } @$subfolders)
{
$folder = enc_untaint($folder, 'keep_path');
# can never be too safe...
if($folder =~ /^\Q$PREF{uploaded_files_realpath}\E/)
{
if($PREF{uploaded_files_realpath} =~ /^\Q$PREF{DOCROOT}\E/)
{
#print STDERR "rmdir-ing $folder\n";
rmdir($folder) or die qq`$0: couldn't rmdir (delete) directory "$folder": $!\n`;
}
else
{
die qq`$0: refusing to rmdir "$folder" because \$PREF{uploaded_files_realpath} ($PREF{uploaded_files_realpath}) does not appear to be within \$PREF{DOCROOT} ($PREF{DOCROOT}).\n`;
}
}
else
{
die qq`$0: refusing to rmdir "$folder" because it doesn't appear to be within \$PREF{uploaded_files_realpath} ($PREF{uploaded_files_realpath}).\n`;
}
}
# finally, delete the requested folder itself.
#
# can never be too safe...
if($dir =~ /^\Q$PREF{uploaded_files_realpath}\E/)
{
$dir = enc_untaint($dir, 'keep_path');
if($PREF{uploaded_files_realpath} =~ /^\Q$PREF{DOCROOT}\E/)
{
#print STDERR "rmdir-ing $dir\n";
rmdir($dir) or die qq`$0: couldn't rmdir (delete) directory "$dir": $!\n`;
}
else
{
die qq`$0: refusing to rmdir "$dir" because \$PREF{uploaded_files_realpath} ($PREF{uploaded_files_realpath}) does not appear to be within \$PREF{DOCROOT} ($PREF{DOCROOT}).\n`;
}
}
else
{
die qq`$0: refusing to rmdir "$dir" because it doesn't appear to be within \$PREF{uploaded_files_realpath} ($PREF{uploaded_files_realpath}).\n`;
}
return \@infofile_errors;
}
sub delete_files_and_folders_older_than
{
my $ttl = shift;
my $dir = $PREF{uploaded_files_realpath_static};
my ($files, $subfolders) = get_items($dir);
my @infofile_errors = ();
# first delete the files.
#
foreach my $file (@$files)
{
$file = enc_untaint($file, 'keep_path');
# can never be too safe...
if($file =~ /^\Q$PREF{uploaded_files_realpath}\E/)
{
if($PREF{uploaded_files_realpath} =~ /^\Q$PREF{DOCROOT}\E/)
{
if(item_is_older_than($file, $ttl))
{
#print STDERR "unlinking $file\n";
unlink($file) or die qq`$0: couldn't unlink (delete) file "$file": $!\n`;
my ($file_with_urlpath) = ($file =~ /^\Q$PREF{DOCROOT}\E(.+$)/);
if(-e (my $infofile = get_info_filename_withpath($file_with_urlpath)) )
{
#print STDERR "deleting $infofile\n";
unlink($infofile) or push @infofile_errors, qq`$0: couldn't unlink (delete) infofile "$infofile": $!\n`;
}
}
}
else
{
die qq`$0: refusing to unlink "$file" because \$PREF{uploaded_files_realpath} ($PREF{uploaded_files_realpath}) does not appear to be within \$PREF{DOCROOT} ($PREF{DOCROOT}).\n`;
}
}
else
{
die qq`$0: refusing to unlink "$file" because it doesn't appear to be within \$PREF{uploaded_files_realpath} ($PREF{uploaded_files_realpath}).\n`;
}
}
# next delete the folders.
# start with the longest pathname to ensure we delete subdirectories before parent directories.
#
foreach my $folder (sort { length($b) <=> length($a) } @$subfolders)
{
$folder = enc_untaint($folder, 'keep_path');
# can never be too safe...
if($folder =~ /^\Q$PREF{uploaded_files_realpath}\E/)
{
if($PREF{uploaded_files_realpath} =~ /^\Q$PREF{DOCROOT}\E/)
{
if(item_is_older_than($folder, $ttl))
{
if(count_items($folder) > 0)
{
warn qq`$0: won't attempt to rmdir directory "$folder" because it isn't empty.\n`;
}
else
{
#print STDERR "rmdir-ing $folder\n";
rmdir($folder) or die qq`$0: couldn't rmdir (delete) directory "$folder": $!\n`;
}
}
}
else
{
die qq`$0: refusing to rmdir "$folder" because \$PREF{uploaded_files_realpath} ($PREF{uploaded_files_realpath}) does not appear to be within \$PREF{DOCROOT} ($PREF{DOCROOT}).\n`;
}
}
else
{
die qq`$0: refusing to rmdir "$folder" because it doesn't appear to be within \$PREF{uploaded_files_realpath} ($PREF{uploaded_files_realpath}).\n`;
}
}
return \@infofile_errors;
}
sub item_is_older_than
{
my $item = shift;
my $allowed_hours = shift;
my $mtime = (stat($item))[9];
my $current_time = time;
return unless ($mtime =~ /^\d{2,}$/ && $current_time =~ /^\d{2,}$/);
my $age_in_seconds = $current_time - $mtime;
my $age_in_hours = $age_in_seconds / 3600;
if($age_in_hours > $allowed_hours)
{
print STDERR "item_is_older_than(): item $item has age $age_in_hours, which exceeds allowed hours ($allowed_hours).\n";
return 1;
}
else
{
return 0;
}
}
sub count_items
{
my $dir = shift;
return scan_dir_for_contents($dir, 'return_the_item_counts');
}
# fc, photos
sub get_items
{
my $dir = shift;
return scan_dir_for_contents($dir, 'return_the_items_themselves');
}
# fc, photos
sub scan_dir_for_contents
{
my $dir = shift;
my $mode = shift;
my @all_dirs = ($dir);
my @all_subdirs = get_all_subdirs($dir);
for(@all_subdirs)
{
push @all_dirs, $dir . '/' . $_;
}
my @all_files = ();
foreach my $subdir (@all_dirs)
{
opendir(SCANDIRFH, $subdir) or die "$0: 22 couldn't open directory $subdir: $!\n";
my $dirh = \*SCANDIRFH; # voodoo required since ancient Perls can't accept "open(my $foo_fh)".
my @files = grep { ! -d "$subdir/$_" } readdir($dirh);
closedir $dirh or die "$0: couldn't close directory $subdir: $!\n";
for(@files)
{
push @all_files, $subdir . '/' . $_;
}
#print STDERR "subdir $subdir contains:" . join ", ", @files;
}
if($mode eq 'return_the_items_themselves')
{
my @all_subdirs_with_paths = ();
for(@all_subdirs)
{
push @all_subdirs_with_paths, $dir . '/' . $_;
}
return (\@all_files, \@all_subdirs_with_paths);
}
elsif($mode eq 'return_the_item_counts')
{
return ($#all_files + 1, $#all_subdirs + 1);
}
}
# fc, photos
sub get_all_subdirs
{
my $dir = shift;
unless(-d $dir)
{
print_server_headers();
print qq`<p>Error: get_all_subdirs(): we need a directory, but we received "$dir".</p>\n`;
return;
}
opendir(DIRHFORALLSUBDIRS, $dir) or die "$0: 33 couldn't open directory $dir: $!\n";
my @dirs = sort grep { -d "$dir/$_" && -w "$dir/$_" && !/^\.$/ && !/\.{2}/ } readdir(DIRHFORALLSUBDIRS);
closedir DIRHFORALLSUBDIRS or die "$0: couldn't close directory $dir: $!\n";
my @subdirs = ();
# now recurse through everything below this point.
foreach my $level1dir (@dirs)
{
foreach my $level2dir (get_all_subdirs("$dir/$level1dir"))
{
push @subdirs, "$level1dir/$level2dir";
}
}
push @dirs, @subdirs;
return @dirs;
}
sub get_userdir
{
my $userdir = ();
return unless $PREF{enable_userdirs} =~ /yes/i;
return if $PREF{admin_is_logged_in}; # because admins should be able to browse all user's dirs, and upload to anywhere they want.
if($PREF{integrate_with_UserBase} =~ /yes/i)
{
$userdir = $PREF{logged_in_username} or exit_with_message("Error: not logged in", qq`Perhaps you need to <a href="$PREF{login_url}">log in</a> first?`);
}
elsif($PREF{enable_userdir_from_cookie} =~ /yes/i)
{
$userdir = get_cookie($PREF{userdir_cookie_name}) or exit_with_message("Error: not logged in", qq`Perhaps you need to <a href="/">go home</a> and log in first?`);
}
elsif($PREF{enable_userdir_on_url} =~ /yes/i)
{
if($qs =~ /(?:^|&)userdir=(.+?)(?:&|$)/)
{
$userdir = $1;
}
elsif($PREF{serial_is_userdir} =~ /yes/i && $PREF{serial} =~ /^\d+$/)
{
$userdir = $PREF{serial};
}
else
{
if($PREF{url_without_userdir_is_error} =~ /yes/i)
{
exit_with_message("Error: malformed URL", qq`You need to pass userdir=yourusername on the URL.`);
}
# if no userdir was passed, and the webmaster doesn't want that to be
# an error, then we just have to return null and use the top-level
# dir for this upload.
}
}
unless($PREF{allow_unsafe_userdir_names} =~ /yes/i)
{
$userdir = enc_untaint($userdir) if $userdir;
}
return $userdir;
}
sub item_is_allowed_to_be_displayed
{
my $item = shift;
my $allowed = 1;
if($PREF{only_show_files_with_these_extensions} =~ /(.+)/)
{
my %allowed_extensions = map { lc($_) => 1 } split(/[,\s]+/, $PREF{only_show_files_with_these_extensions});
my ($this_items_extension) = ($item =~ /.*(\..+)$/);
die qq`$0: could not determine the extension for item "$item".\n` unless ($this_items_extension || $PREF{allow_files_without_extensions} =~ /yes/i);
unless( $allowed_extensions{lc($this_items_extension)} )
{
$allowed = 0;
}
}
if($PREF{hide_files_with_these_extensions} =~ /(.+)/)
{
my %disallowed_extensions = map { lc($_) => 1 } split(/[,\s]+/, $PREF{hide_files_with_these_extensions});
my ($this_items_extension) = ($item =~ /.*(\..+)$/);
die qq`$0: could not determine the extension for item "$item".\n` unless ($this_items_extension || $PREF{allow_files_without_extensions} =~ /yes/i);
if( $disallowed_extensions{lc($this_items_extension)} )
{
$allowed = 0;
}
}
return $allowed;
}
sub clean_up_filename
{
s/\s+/_/g for @_;
s/[^0-9A-Za-z\._-]//g for @_;
}
sub store_upload_info
{
my ($i, $filename_with_urlpath, $filename_with_localpath, $filesize, $serial, $textboxes) = @_; # $textboxes is a hashref.
my %INFO = ();
($INFO{filepath}, $INFO{filename}) = ($filename_with_localpath =~ m!^(.*[/\\])(.+)$!);
$INFO{origpath} = $INFO{filepath};
$INFO{origname} = $INFO{filename};
$INFO{filesize} = $filesize;
$INFO{uploadsize} = $ENV{CONTENT_LENGTH};
$INFO{filecount} = $PREF{uploaddata}{$serial}{totalfiles};
$INFO{serial} = $serial;
($INFO{ip},$INFO{host}) = get_ip_and_host();
$INFO{userdir} = get_userdir() ? get_userdir() : '(none)';
$INFO{username} = $PREF{logged_in_username} ? $PREF{logged_in_username} : '(none)';
$INFO{useragent} = $ENV{HTTP_USER_AGENT};
$INFO{startetime} = $PREF{uploaddata}{$serial}{start_time};
my $start_ampm = lc(strftime("%p", localtime($INFO{startetime})));
$INFO{starttime} = strftime("%a%b%d,%Y,%I:%M", localtime($INFO{startetime})).$start_ampm;
$INFO{endetime} = time + $PREF{time_offset};
my $end_ampm = lc(strftime("%p", localtime($INFO{endetime})));
$INFO{endtime} = strftime("%a%b%d,%Y,%I:%M", localtime($INFO{endetime})).$end_ampm;
$INFO{elapsecs} = $INFO{endetime} - $INFO{startetime};
$INFO{elapmins} = $INFO{elapsecs} / 60;
$INFO{elaphours} = $INFO{elapsecs} / 3600;
s/(.*\.\d).*/$1/ for ($INFO{elapmins}, $INFO{elaphours});
if($PREF{store_upload_info_in_database} =~ /yes/i)
{
# get any custom textbox values.
foreach my $textbox (keys %$textboxes)
{
my $textbox_without_filenumber = $textbox;
$textbox_without_filenumber =~ s/_\d+$//; # remove trailing digit in case this is a perfile textbox.
my $dbcolname = $PREF{"${textbox_without_filenumber}_dbcolname"};
if($dbcolname)
{
if($textbox ne $textbox_without_filenumber) # then it's a perfile textbox
{
if($textbox =~ /_$i$/) # make sure we get the value from the textbox for the proper file (the one ending in the current $i)
{
$INFO{$dbcolname} = $$textboxes{$textbox}{value};
}
}
else
{
$INFO{$dbcolname} = $$textboxes{$textbox}{value};
}
}
}
my $query = qq`INSERT INTO $PREF{db_table_for_upload_info} ($PREF{db_columns_for_upload_info}) VALUES(`;
foreach my $col (split(/,/, $PREF{db_columns_for_upload_info}))
{
$INFO{$col} =~ s/'/\\'/g;
$query .= qq`'$INFO{$col}',`;
}
$query =~ s/,$//;
$query .= qq`);`;
my $sth = $dbh->prepare($query);
$sth->execute() or die "$0: store_upload_info(): $DBI::errstr\n";
}
if($PREF{store_upload_info_in_files} =~ /yes/i)
{
my $infofile = get_info_filename_withpath($filename_with_localpath);
# The name of the infofile is taken from the name of the uploaded file itself,
# and it gets serialized along with the name of the uploaded file. So the only
# way that the infofile could already exist is if someone deleted the uploaded
# file outside of FileChucker (via shell, FTP, etc) and left the infofile behind.
# In that case, the infofile no longer has an uploaded file to be attached to, so
# we'd want to overwrite it anyway. So don't die here if the infofile already
# exists.
#
#die_nice(qq`Error: the infofile ($infofile) for this upload ($filename_with_urlpath) already exists.`) if -e $infofile;
open(UPLOADINFOOUTFH, ">$infofile") or die "$0: couldn't create infofile $infofile: $!\n";
my $outfh = \*UPLOADINFOOUTFH; # voodoo required since ancient Perls can't accept "open(my $foo_fh)".
flock $outfh, 2;
seek $outfh, 0, 0;
my $labels = get_fileinfo_labels();
print $outfh
qq`$$labels{origname}$filename_with_localpath`
. qq`\n$$labels{filesize}$INFO{filesize}`
. qq`\n$$labels{uploadsize}$INFO{uploadsize}`
. qq`\n$$labels{filecount}$INFO{filecount}`
. qq`\n$$labels{serial}$INFO{serial}`
. qq`\n`
. qq`\n$$labels{ip}$INFO{ip}`
. qq`\n$$labels{host}$INFO{host}`
. qq`\n$$labels{userdir}$INFO{userdir}`
. qq`\n$$labels{username}$INFO{username}`
. qq`\n$$labels{useragent}$INFO{useragent}`
. qq`\n`
. qq`\n$$labels{starttime}$INFO{starttime}`
. qq`\n$$labels{endtime}$INFO{endtime}`
. qq`\n`
. qq`\n$$labels{startetime}$INFO{startetime}`
. qq`\n$$labels{endetime}$INFO{endetime}`
. qq`\n`
. qq`\n$$labels{elapsecs}$INFO{elapsecs}`
. qq`\n$$labels{elapmins}$INFO{elapmins}`
. qq`\n$$labels{elaphours}$INFO{elaphours}`
. qq`\n`;
my $textbox_values = get_textbox_values('all', $i, $textboxes, 'text', 'show_field_keynames', '!!replace_NEWLINEs', '!!mark_headings');
print $outfh $textbox_values;
truncate $outfh, tell $outfh;
close $outfh or die "$0: couldn't close infofile $infofile after creating it: $!\n";
chmod 0666, $infofile;
}
my $textbox_values_for_qs = get_textbox_values('all', undef, $textboxes, 'text', 'show_field_keynames', '!!replace_NEWLINEs', '!!mark_headings');
return $textbox_values_for_qs;
}
sub get_fileinfo_labels
{
my %labels = (
filename => 'Current filename: ',
origname => 'Original filename: ',
filesize => 'File size: ',
filecount => 'Uploaded in a group of this many files: ',
uploadsize => 'Total upload size: ',
serial => 'Upload serial number: ',
ip => "Uploader's IP address: ",
host => "Uploader's hostname: ",
userdir => "Uploader's user-dir: ",
username => "Uploader's username: ",
useragent => "Uploader's user-agent: ",
starttime => 'Start time (for entire upload): ',
endtime => 'End time (for entire upload): ',
startetime => 'Start etime (for entire upload): ',
endetime => 'End etime (for entire upload): ',
elapsecs => 'Elapsed time in seconds (for entire upload): ',
elapmins => 'Elapsed time in minutes (for entire upload): ',
elaphours => 'Elapsed time in hours (for entire upload): '
);
return \%labels;
}
sub format_filesize_nicely
{
my $rawsize = my $size = shift;
$size = 0 unless $size;
$size = $size > 999999 ? onedecimal($size/(1024*1024)) . " $PREF{MB}" : int($size/1024) . " $PREF{KB}";
$size =~ s/^0 /1 / if $rawsize > 0; # for tiny files, round to 1 instead of 0.
return $size;
}
sub remove_reserved_strings
{
s/-\.-\.-/_._._/g for @_; # because we use -.-.- as a directory-separation symbol in our infofiles' filenames.
}
sub show_fileinfo
{
print_needlogin_error_and_exit() unless user_is_allowed_to('view_upload_info');
my $path = shift;
my $file = shift;
enc_urldecode($path, $file);
$file = enc_untaint($file);
$path = enc_untaint($path, 'keep_path') if $path;
#clean_up_filename($dst) if $PREF{clean_up_filenames} =~ /yes/i;
#remove_reserved_strings($dst);
my %textboxes = ();
start_html_output('Upload Info', 'css', 'js');
print qq`<h1>Upload Info</h1>\n\n`;
if($PREF{store_upload_info_in_database} =~ /yes/i)
{
print "<!-- (info from db) -->\n";
$path .= '/' if(!$path || $path !~ m!/$!);
$path = "/$path" unless $path =~ m!^/!;
# make a hash of our built-in fields, so we can properly detect custom fields.
my $builtin_info_fields = 'filepath,filename,origpath,origname,filesize,uploadsize,filecount,serial,ip,host,userdir,username,useragent,starttime,endtime,startetime,endetime,elapsecs,elapmins,elaphours';
my %builtin_info_fields = map { $_ => 1 } split(/,/, $builtin_info_fields);
my $labels = get_fileinfo_labels();
my %INFO = ();
my $query = qq`SELECT $PREF{db_columns_for_upload_info} FROM $PREF{db_table_for_upload_info} WHERE filename='$file' AND filepath='$path' LIMIT 1`;
print STDERR "query=$query\n";
my $fileinfo = $dbh->selectrow_hashref($query);
my $name_and_path_done = 0;
foreach my $field (split(/,/, $PREF{db_columns_for_upload_info}))
{
if($field eq 'filepath' || $field eq 'filename' || $field eq 'origpath' || $field eq 'origname')
{
next if $name_and_path_done;
if($fileinfo->{filepath} && $fileinfo->{filename}) { print qq`\n<div style="text-align: left;"><span style="font-family: monospace;">$$labels{filename}</span>$fileinfo->{filepath}$fileinfo->{filename}</div>\n`; }
if($fileinfo->{origpath} && $fileinfo->{origname}) { print qq`\n<div style="text-align: left;"><span style="font-family: monospace;">$$labels{origname}</span>$fileinfo->{origpath}$fileinfo->{origname}</div>\n`; }
print qq`<pre style="text-align: left; font-family: monospace;">\n`;
$name_and_path_done = 1;
}
elsif($field eq 'useragent')
{
print qq`</pre>\n<div style="text-align: left;"><span style="font-family: monospace;">$$labels{$field}</span>$fileinfo->{$field}</div>\n<pre style="text-align: left; font-family: monospace;">`;
}
elsif($field eq 'filesize' || $field eq 'uploadsize')
{
my $value = format_filesize_nicely($fileinfo->{$field}) if $fileinfo->{$field} =~ /^\d+$/;
print "$$labels{$field}$value\n";
}
#elsif($line =~ /^(top|perfile|bottom)_textboxes_title/)
#{
#
#}
elsif($field eq 'endtime' || $field eq 'endetime')
{
# print an extra newline for these two, just to make the output nicer.
print "$$labels{$field}$fileinfo->{$field}\n";
print "\n";
}
elsif($builtin_info_fields{$field})
{
print "$$labels{$field}$fileinfo->{$field}\n";
}
else # else it's a custom textbox.
{
foreach my $key (keys %PREF)
{
if($key =~ /^((top|perfile|bottom)_textbox_\d+_(?:single|multi)line)_dbcolname$/)
{
my $textbox = $1;
my $type = $2;
my $textbox_name = $PREF{$textbox};
my $dbcolname = $PREF{$key};
if($field eq $dbcolname)
{
# The get_textbox_values() function into which %textboxes will be passed is
# expecting any perfile textboxes to end in _N. In this context though, we're
# only dealing with a single file (showing its fileinfo), so we don't know
# the value of N; but in fact, we don't need it either -- we just need to
# stick an arbitrary digit onto there so the function processes it correctly.
$textbox .= '_1' if $type eq 'perfile';
$textboxes{$textbox}{name} = $textbox_name;
$textboxes{$textbox}{value} = $fileinfo->{$field};
}
}
}
}
}
print qq`</pre>\n\n`;
}
elsif($PREF{store_upload_info_in_files} =~ /yes/i)
{
print "<!-- (info from file) -->\n";
my @contents = ();
my $infofile = get_info_filename_withpath("$path$file");
die_nice(qq`Error: couldn't find info file for $path$file.`) unless -e $infofile;
open(FILEINFOINFH, "<$infofile") or die "$0: couldn't open infofile $infofile for reading: $!\n";
my $infh = \*FILEINFOINFH; # voodoo required since ancient Perls can't accept "open(my $foo_fh)".
flock $infh, 1;
seek $infh, 0, 0;
@contents = <$infh>;
close $infh or die "$0: couldn't close infofile $infofile after reading: $!\n";
my $closed_pretag_already = 0;
foreach my $line (@contents)
{
if($line =~ /^(Original filename: )(.*)$/)
{
print qq`\n<div style="text-align: left;"><span style="font-family: monospace;">$1</span>$2</div>\n<pre style="text-align: left; font-family: monospace;">`;
}
elsif($line =~ /^(Uploader's user-agent: )(.*)$/)
{
print qq`</pre>\n<div style="text-align: left;"><span style="font-family: monospace;">$1</span>$2</div>\n<pre style="text-align: left; font-family: monospace;">`;
}
elsif($line =~ /^(Uploader's comments:)$/)
{
print qq`</pre>\n<div class="uploader-comments"><span style="font-weight: bold;">$1</span>`;
$closed_pretag_already = 1;
}
elsif($closed_pretag_already)
{
print '<br />' . $line;
}
elsif($line =~ /^((?:File|Total upload) size: )(.*)$/)
{
my ($label,$value) = ($1,$2);
$value = format_filesize_nicely($value) if $value =~ /^\d+$/;
print "$label$value\n";
}
elsif($line =~ /^(End time|End etime|Total upload size)/)
{
print $line . "\n";
}
elsif($line =~ /^(top|perfile|bottom)_textboxes_title/)
{
}
elsif($line =~ /^((?:top|perfile|bottom)_textbox_\d+_(?:single|multi)line(?:_\d+)?):(name|value): (.*)$/)
{
$textboxes{$1}{$2} = $3;
}
else
{
if($line =~ /\S/)
{
print $line;
}
}
}
print qq`\n</div>` if $closed_pretag_already;
print qq`\n</pre>` unless $closed_pretag_already;
}
print qq`\n\n`;
my $textbox_values = get_textbox_values('all', undef, \%textboxes, 'html', '!!show_field_keynames', 'replace_NEWLINEs', 'mark_headings');
print qq`\n<h1>Uploader's Textbox Entries:</h2>\n<div style="text-align: left;"><br />$textbox_values</div>\n\n` if $textbox_values;
print_footer_links('home','uploader','list');
finish_html_output();
}
sub get_info_filename_withpath
{
my $filename = shift;
#print STDERR "get_info_filename_withpath(): got filename $filename\n";
my $infofile = $filename;
my $userdir = get_userdir();
if($userdir)
{
# If get_userdir() returns a directory (i.e. if userdirs are enabled and
# a non-admin is logged in) then we need to prepend that to the infofile
# name, so that it has the correct path. This is necessary so that when
# an admin is logged in, the infofile links still work; otherwise they
# would be missing that userdir portion at the front.
$infofile = $userdir . '/' . $infofile;
}
$infofile =~ s!^[/\\]+!!; # we never want a slash (which turns into "-.-.-") at the front of the filename.
$infofile =~ s![/\\]{2,}!/!g;
$infofile =~ s![/\\]!-.-.-!g;
my $slash = $PREF{datadir} =~ m!/$! ? undef : '/';
$infofile = $PREF{datadir} . $slash . $infofile . '.info.txt';
#print STDERR "get_info_filename_withpath(): returning filename $infofile\n";
return $infofile;
}
sub move_all_infofiles($$$)
{
my $files = shift; # arrayref [ from: my ($files, $subfolders) = get_items($srcdir); ]
my $srcdir_with_url = shift;
my $dstdir_with_url = shift;
my @errors = ();
foreach my $file (@$files)
{
$file = enc_untaint($file, 'keep_path');
my ($file_with_localpath_only) = ($file =~ m!$PREF{uploaded_files_realpath}/?(.+?)$!);
#print STDERR "file_with_localpath_only: $file_with_localpath_only\n";
my $old_infofile = get_info_filename_withpath($file_with_localpath_only);
my ($file_with_old_path_removed) = ($file =~ /$srcdir_with_url(.+$)/);
#print STDERR "file_with_old_path_removed: $file_with_old_path_removed\n";
my $file_with_new_path_added = $dstdir_with_url . $file_with_old_path_removed;
my ($newfile_with_localpath_only) = ($file_with_new_path_added =~ m!$PREF{uploaded_files_urlpath}/?(.+?)$!);
#print STDERR "newfile_with_localpath_only: $newfile_with_localpath_only\n";
my $new_infofile = get_info_filename_withpath($newfile_with_localpath_only);
if(-e $old_infofile)
{
rename($old_infofile, $new_infofile) or push @errors, qq`couldn't move infofile from "$old_infofile" to "$new_infofile": $!`;
}
if($PREF{store_upload_info_in_database} =~ /yes/i)
{
my ($oldpath, $filename) = ($file_with_localpath_only =~ m!^(.*?/?)([^/]+)$!);
my ($file_with_old_path_removed) = ($file =~ /$srcdir_with_url(.+$)/);
my $file_with_new_path_added = $dstdir_with_url . $file_with_old_path_removed;
my ($newfile_with_localpath_only) = ($file_with_new_path_added =~ m!$PREF{uploaded_files_urlpath}/?(.+?)$!);
my $newpath = $newfile_with_localpath_only;
$newpath =~ s![^/]+$!!; # remove the filename (i.e. everything from the right-end up to the slash).
slashify($oldpath, $newpath);
#print STDERR "move_all_infofiles: oldpath=$oldpath, newpath=$newpath, filename=$filename\n";
my $query = qq`UPDATE $PREF{db_table_for_upload_info} SET filepath='$newpath' WHERE filename='$filename' AND filepath='$oldpath' LIMIT 1;`;
#print STDERR "move_all_infofiles: query=$query\n";
my $sth = $dbh->prepare($query);
my $success = $sth->execute();
if(!$success || $success =~ /^(0|0E0)$/)
{
push(@errors, qq`couldn't update filepath from '$oldpath' to '$newpath' for filename '$filename' in upload info database: $DBI::errstr`);
}
}
}
return \@errors;
}
sub show_link_to_uploads
{
# The uploaded_files_urlpath must exist (i.e. uploaded_files_dir either must be
# in the DOCROOT or else the webmaster must have set uploaded_files_urlpath
# explicitly), or download_links_go_through_FileChucker must be set; and the
# show_link_to_uploads... PREF must be set.
return
(
(
$PREF{uploaded_files_urlpath}
||
$PREF{download_links_go_through_FileChucker} =~ /yes/i
)
&&
(
$PREF{show_link_to_uploads_for_strangers} =~ /yes/i
||
($PREF{show_link_to_uploads_for_members} =~ /yes/i && $PREF{member_is_logged_in})
||
($PREF{show_link_to_uploads_for_admins} =~ /yes/i && $PREF{admin_is_logged_in})
)
);
}
sub interpolate_vars_from_URL_and_cookies
{
my %url_vars = ();
for(split(/&/, $qs))
{
my ($var,$value) = split(/=/);
enc_urldecode($value);
$url_vars{$var} = $value;
}
s/%URL\{(.+?)\}/$url_vars{$1}/g for @_;
s/%COOKIE\{(.+?)\}/get_cookie($1)/eg for @_;
}
# The string returned by this function must end with an ampersand (unless it's null).
sub get_userdir_for_qs
{
my $userdir = get_userdir() if $PREF{enable_userdirs} =~ /yes/i && $PREF{enable_userdir_on_url} =~ /yes/i;
$userdir = "userdir=$userdir&" if $userdir;
return $userdir;
}
# The string returned by this function must end with an ampersand (unless it's null).
sub get_path_and_userdir_for_qs
{
my $userdir = get_userdir_for_qs();
my ($path) = ($qs =~ /(?:^|&)path=(.*?)(?:&|$)/);
my $output = ();
$output .= $userdir if $userdir;
$output .= "path=$path&" if $path;
return $output;
}
#sub print_not_allowed_error_and_exit
#{
# my $login_url = $PREF{integrate_with_UserBase} =~ /yes/i ? $PREF{login_url} : "$PREF{here_login}?action=login";
# start_html_output('Authentication Required', 'css', 'js');
# print qq`<h2>Authentication Required</h2>`
# . qq`\n<div>You don't have permission to do that. Perhaps you need to <a href="$login_url">log in</a> first?</div>`
# . qq`\n`;
# print_footer_links('home','uploader','list');
# finish_html_output();
# exit;
#}
sub get_textboxes
{
return unless $PREF{store_upload_info_in_files} =~ /yes/i;
my $position = shift;
my $i = shift;
my $enabled = 0;
my $output = qq`<div id="${position}-textboxes" class="clearfixtb">\n`;
$output .= qq`\t<div id="${position}-textboxes-title">$PREF{"${position}_textboxes_title"}</div>\n` if $PREF{"${position}_textboxes_title"} =~ /\S/;
foreach my $textbox (sort keys %PREF)
{
if($textbox =~ /^${position}_textbox_(\d+)_(single|multi)line$/)
{
my ($num,$type) = ($1,$2);
$enabled = 1;
if($PREF{"${textbox}_before"} =~ /\S/) { $output .= $PREF{"${textbox}_before"}; }
my ($w,$h) = ($PREF{"${textbox}_size"} =~ /(\d+)x(\d+)/i);
my $oldvalue = get_cookie($textbox) if $PREF{"${textbox}_save"} =~ /yes/i;
my $name = $i ? "${textbox}_$i" : $textbox;
my $required = $PREF{"${textbox}_required"} =~ /yes/i ? ' required' : undef;
my $emailformat = $PREF{"${textbox}_email"} =~ /yes/i ? ' emailformat' : undef;
if($PREF{"${textbox}_dropdown"} =~ /\S/)
{
$output .= qq`<div class="clearfixtb $textbox"><div class="textboxes-label">$PREF{$textbox}</div>`;
$output .= qq`<select name="$name" class="$textbox$required">`;
my @options = split(/\|\|\|/, $PREF{"${textbox}_dropdown"});
foreach my $option (@options)
{
$output .= qq`<option value="$option"` . ($option eq $oldvalue ? ' selected="selected"' : undef) . qq`>$option</option>`;
}
$output .= qq`</select>`;
$output .= qq`</div>\n`;
}
elsif($type eq 'single')
{
$output .= qq`<div class="clearfixtb $textbox"><div class="textboxes-label">$PREF{$textbox}</div><input type="text" name="$name" class="$textbox$required$emailformat" value="$oldvalue" /></div>\n`;
}
else
{
$output .= qq`<div class="clearfixtb $textbox"><div class="textboxes-label">$PREF{$textbox}</div><textarea name="$name" class="$textbox$required" style="width: ${w}px; height: ${h}px;">$oldvalue</textarea></div>\n`;
}
if($PREF{"${textbox}_after"} =~ /\S/) { $output .= $PREF{"${textbox}_after"}; }
}
}
$output .= qq`</div>\n\n\n`;
return $enabled ? $output : undef;
}
sub get_textbox_values
{
my $mode = shift; # top, bottom, perfile, or all.
my $i = shift; $i = '\d+' if !$i && $mode eq 'all';
my $textboxes = shift; # hashref.
my $format = shift; my $newline = $format eq 'html' ? '<br />' : "\n";
my $show_field_keynames = shift; $show_field_keynames = $show_field_keynames eq 'show_field_keynames' ? 1 : 0;
my $replace_NEWLINEs = shift; $replace_NEWLINEs = $replace_NEWLINEs eq 'replace_NEWLINEs' ? 1 : 0;
my $mark_headings = shift; $mark_headings = $mark_headings eq 'mark_headings' ? 1 : 0;
my $output = ();
if($mode =~ /^top|all$/)
{
if($PREF{top_textboxes_title} =~ /\S/)
{
$output .= qq`top_textboxes_title: ` if $show_field_keynames;
if($mark_headings)
{
$output .= $newline eq "\n" ? '=' x 70 . "\n" . $PREF{top_textboxes_title} . "\n" . '=' x 70 . "\n\n" : '<h2>' . $PREF{top_textboxes_title} . '</h2>';
}
else { $output .= $PREF{top_textboxes_title}; }
}
foreach my $tb (sort keys %$textboxes)
{
if($tb =~ /^top_textbox_\d+_(single|multi)line$/)
{
$output .= $newline . $newline unless $mark_headings;
$output .= qq`$tb:name: ` if $show_field_keynames;
if($mark_headings && $$textboxes{$tb}{name})
{
$output .= $newline eq "\n" ? $$textboxes{$tb}{name} . "\n\n" : '<h3>' . $$textboxes{$tb}{name} . '</h3>';
}
else { $output .= $$textboxes{$tb}{name}; }
$output .= $newline . $newline unless $mark_headings;
$output .= qq`$tb:value: ` if $show_field_keynames;
$output .= $$textboxes{$tb}{value} . $newline . $newline;
$output .= '-' x 50 . "\n\n" if $mark_headings && $newline eq "\n";
}
}
$output .= $newline . $newline if $output;
}
if($mode =~ /^perfile|all$/)
{
if($PREF{perfile_textboxes_title} =~ /\S/)
{
$output .= qq`perfile_textboxes_title: ` if $show_field_keynames;
if($mark_headings)
{
$output .= $newline eq "\n" ? '=' x 60 . "\n" . $PREF{perfile_textboxes_title} . "\n" . '=' x 60 . "\n\n" : '<h2>' . $PREF{perfile_textboxes_title} . '</h2>';
}
else { $output .= $PREF{perfile_textboxes_title}; }
}
foreach my $tb (sort keys %$textboxes)
{
if($tb =~ /^perfile_textbox_\d+_(single|multi)line_$i$/)
{
$output .= $newline . $newline unless $mark_headings;
$output .= qq`$tb:name: ` if $show_field_keynames;
if($mark_headings && $$textboxes{$tb}{name})
{
$output .= $newline eq "\n" ? $$textboxes{$tb}{name} . "\n\n" : '<h3>' . $$textboxes{$tb}{name} . '</h3>';
}
else { $output .= $$textboxes{$tb}{name}; }
$output .= $newline . $newline unless $mark_headings;
$output .= qq`$tb:value: ` if $show_field_keynames;
$output .= $$textboxes{$tb}{value} . $newline . $newline;
$output .= '-' x 50 . "\n\n" if $mark_headings && $newline eq "\n";
}
}
$output .= $newline . $newline if $output;
}
if($mode =~ /^bottom|all$/)
{
if($PREF{bottom_textboxes_title} =~ /\S/)
{
$output .= qq`bottom_textboxes_title: ` if $show_field_keynames;
if($mark_headings)
{
$output .= $newline eq "\n" ? '=' x 70 . "\n" . $PREF{bottom_textboxes_title} . "\n" . '=' x 70 . "\n\n" : '<h2>' . $PREF{bottom_textboxes_title} . '</h2>';
}
else { $output .= $PREF{bottom_textboxes_title}; }
}
foreach my $tb (sort keys %$textboxes)
{
if($tb =~ /^bottom_textbox_\d+_(single|multi)line$/)
{
$output .= $newline . $newline unless $mark_headings;
$output .= qq`$tb:name: ` if $show_field_keynames;
if($mark_headings && $$textboxes{$tb}{name})
{
$output .= $newline eq "\n" ? $$textboxes{$tb}{name} . "\n\n" : '<h3>' . $$textboxes{$tb}{name} . '</h3>';
}
else { $output .= $$textboxes{$tb}{name}; }
$output .= $newline . $newline unless $mark_headings;
$output .= qq`$tb:value: ` if $show_field_keynames;
$output .= $$textboxes{$tb}{value} . $newline . $newline;
$output .= '-' x 50 . "\n\n" if $mark_headings && $newline eq "\n";
}
}
$output .= $newline . $newline if $output;
}
$output =~ s/ ::NEWLINE:: /$newline/g if $replace_NEWLINEs;
# Note that this function is written so that output is null if none of
# the appropriate PREFs are set.
return $output;
}
sub download_file
{
print_needlogin_error_and_exit() unless user_is_allowed_to('download');
my $path = shift;
my $file = shift;
enc_urldecode($path, $file);
$file = enc_untaint($file);
$path = enc_untaint($path, 'keep_path') if $path;
my $fullfile = "$PREF{uploaded_files_realpath}/$path/$file";
$fullfile =~ s!/+!/!g;
select STDOUT;
$| = 1;
my ($read,$buf) = ();
my $size = (stat $fullfile)[7];
print qq`Content-Type: application/octet-stream\n`
. qq`Content-Disposition: attachment; filename=$file\n`
. qq`Content-Length: $size\n`
. qq`Content-Description: Downloadable File\n\n`;
open(DOWNLOADFILEFH, $fullfile) or die "$0: couldn't open file '$fullfile' for reading: $!\n";
my $infh = \*DOWNLOADFILEFH; # voodoo required since ancient Perls can't accept "open(my $foo_fh)".
binmode $infh;
my $blocksize = (stat $infh)[11] ? (stat $infh)[11] : 16384;
while($read = sysread($infh, $buf, $blocksize))
{
unless(defined($read))
{
next if $! =~ /^Interrupted/;
die "$0: download_file(): read error: $!\n";
}
my ($written,$offset) = (0,0);
while($read)
{
$written = syswrite(STDOUT, $buf, $read, $offset);
unless(defined($written))
{
die "$0: download_file(): write error: $!\n";
}
$read -= $written;
$offset += $written;
}
}
close $infh or die "$0: couldn't close file '$fullfile' after reading: $!\n";
if($PREF{update_timestamp_on_download} =~ /yes/i)
{
open(TOUCHFILEFH, ">$fullfile") or die "$0: couldn't open file '$fullfile' for touching: $!\n";
my $touchfh = \*TOUCHFILEFH; # voodoo required since ancient Perls can't accept "open(my $foo_fh)".
close $touchfh or die "$0: couldn't close file '$fullfile' after touching: $!\n";
}
}
sub get_uploaded_files_url_path
{
my $arg = shift;
my $strip_trailing_slash = $arg eq 'without_trailing_slash' ? 1 : 0;
if($PREF{hide_path_to_uploads_dir} =~ /yes/i)
{
return undef;
}
else
{
my $path = $PREF{uploaded_files_urlpath};
$path =~ s!/+$!! if $strip_trailing_slash;
return $path;
}
}
sub print_error
{
my $error = shift;
my $arg1 = shift;
start_html_output('Error', 'css');
if($error eq 'toobig')
{
my $nice_size = format_filesize_nicely($arg1);
my $nice_limit = format_filesize_nicely($CGI::POST_MAX);
print qq`<h1>Error:</h1><p>You tried to send $nice_size, which exceeds the current limit of $nice_limit.</p>\n`;
}
print_footer_links('home', 'pb');
finish_html_output();
}
sub show_loggedout_page
{
my $ref = shift;
enc_urldecode($ref);
start_html_output('Logged Out', 'css', 'js');
print qq`<h1>Logged Out</h1>\n<p>You are logged out.</p>\n`;
print qq`<p><a href="$ref">Click here</a> to return to the page you came from.</p>\n` if $ref;
print_footer_links('home','uploader','list');
finish_html_output();
}
#####
sub get_cookies()
{
use CGI ':standard';
use CGI::Cookie;
my %cookies = fetch CGI::Cookie;
return %cookies;
}
sub get_cookie($)
{
my $which = shift;
my %jar = get_cookies();
my $value;
if(exists $jar{$which})
{
$value = $jar{$which}->value;
}
return $value;
}
sub set_cookie($$$)
{
my $name = shift;
my $value = shift;
my $expiry = shift;
my $cookie;
# This if/else is necessary because setting "expires" to "" isn't
# the same as not setting it. Setting it to "" is the same as
# setting it to zero, which expires the cookie immediately
# (i.e., deletes it). But explicitly *not* setting the expiry
# causes the cookie to persist until the end of the session.
if($expiry eq "")
{
$cookie = new CGI::Cookie( -name => $name,
-value => $value,
-path => '/');
}
else
{
$cookie = new CGI::Cookie( -name => $name,
-value => $value,
-expires => $expiry,
-path => '/');
}
if($PREF{output_started})
{
warn "$0: warning: cannot set cookie '$name' => '$value' because the page output has already been started.\n";
}
else
{
print "Set-Cookie: $cookie\n";
}
}
sub load_userlist($)
{
my $list = shift;
my ($file, %userlist) = ();
$PREF{userbase_data_dir} = ($PREF{userbase_data_dir_is_in_docroot} =~ /yes/i && $PREF{userbase_data_dir} !~ /^\Q$PREF{DOCROOT}\E/) ? $PREF{DOCROOT} . $PREF{userbase_data_dir} : $PREF{userbase_data_dir};
$PREF{admin_username_file} = $PREF{userbase_data_dir} . '/enc_admins.txt' unless exists $PREF{admin_username_file};
$PREF{member_username_file} = $PREF{userbase_data_dir} . '/enc_members.txt' unless exists $PREF{member_username_file};
if($list eq 'admin') { $file = $PREF{admin_username_file}; }
if($list eq 'member') { $file = $PREF{member_username_file}; }
open(USERLISTFILEFH,"<$file") or die "$0: couldn't open $file: $!\n";
my $infh = \*USERLISTFILEFH; # voodoo required since ancient Perls can't accept "open(my $foo_fh)".
flock $infh, 1;
seek $infh, 0, 0;
while(<$infh>)
{
# the format of each line is:
#
# username:hashed_pw:option1=foo:::::setting2=bar:::::prefN=baz(...)
#
chomp; next if /^\s*(#|$)/;
my ($username, $crypted_actual_password, $options) = split(/:/, $_, 3);
if($username && $crypted_actual_password)
{
$userlist{lc($username)}{pw} = $crypted_actual_password;
foreach my $option (split(/:::::/, $options))
{
if($option =~ /\s*(.+?)\s*=\s*(.+)\s*/)
{
if($1 eq 'pw')
{
die "$0: error: 'pw' is a reserved option/setting/preference. please choose another name.\n";
}
else
{
$userlist{lc($username)}{$1} = $2;
}
}
}
}
}
close $infh or die "$0: couldn't close $file: $!\n";
return \%userlist;
}
sub check_if_logged_in()
{
my %cookies = get_cookies();
if($PREF{integrate_with_existing_login_system} =~ /yes/i && $PREF{integrate_with_UserBase} !~ /yes/i)
{
my $username_in_cookie = ();
if(exists($cookies{$PREF{admin_username_cookie_name}}) && ($username_in_cookie = $cookies{$PREF{admin_username_cookie_name}}->value))
{
return (1, 1, $username_in_cookie);
}
elsif(exists($cookies{$PREF{member_username_cookie_name}}) && ($username_in_cookie = $cookies{$PREF{member_username_cookie_name}}->value))
{
return (0, 1, $username_in_cookie);
}
else
{
return ();
}
}
elsif($PREF{integrate_with_UserBase} =~ /yes/i)
{
$PREF{site_username_cookie} = 'site_username' unless exists $PREF{site_username_cookie};
$PREF{site_password_cookie} = 'site_password' unless exists $PREF{site_password_cookie};
if( (exists $cookies{$PREF{'site_username_cookie'}}) && (exists $cookies{$PREF{'site_password_cookie'}}) )
{
my ($username_in_cookie, $crypted_password_in_cookie, $logged_in_username);
my ($admin_logged_in, $member_logged_in) = (0, 0);
$username_in_cookie = $cookies{$PREF{'site_username_cookie'}}->value;
$crypted_password_in_cookie = $cookies{$PREF{'site_password_cookie'}}->value;
my $member_hashref = load_userlist('member');
if( exists($$member_hashref{lc($username_in_cookie)}) && ($$member_hashref{lc($username_in_cookie)}{'pw'} eq $crypted_password_in_cookie) )
{
$logged_in_username = $username_in_cookie;
$member_logged_in = 1;
}
my $admin_hashref = load_userlist('admin');
if( exists($$admin_hashref{lc($username_in_cookie)}) && ($$admin_hashref{lc($username_in_cookie)}{'pw'} eq $crypted_password_in_cookie) )
{
$logged_in_username = $username_in_cookie;
$admin_logged_in = 1;
# Admins are "members" too:
$member_logged_in = 1;
}
return ($admin_logged_in, $member_logged_in, $logged_in_username);
}
else
{
return ();
}
}
elsif($PREF{admin_password_hash} || $PREF{member_password_hash})
{
my $hashed_password_in_cookie = get_cookie('enc-uploader-password');
if($hashed_password_in_cookie && ($hashed_password_in_cookie eq $PREF{admin_password_hash}))
{
return (1, 1, undef);
}
elsif($hashed_password_in_cookie && ($hashed_password_in_cookie eq $PREF{member_password_hash}))
{
return (0, 1, undef);
}
else
{
return ();
}
}
else
{
return ();
}
}
sub print_notadmin_error_with_link_to_login_page()
{
print qq`<p>You must <a href="$PREF{login_url}">login</a> as an administrator to use that facility.</p>\n`;
}
sub expand_custom_vars_in_prefs($)
{
my $hashref = shift;
foreach my $key (keys %$hashref)
{
# from now on, use %%varname%% instead of $$varname$$, so that it doesn't
# matter whether it gets put in double-quotes.
next unless $$hashref{$key} =~ /(\$\$|%%)/;
# old way:
$$hashref{$key} =~ s/\$\$server_name\$\$/$ENV{'SERVER_NAME'}/g;
$$hashref{$key} =~ s/\$\$httphost_withport\$\$/$ENV{'HTTP_HOST'}/g;
$$hashref{$key} =~ s/\$\$name_of_site\$\$/$$hashref{'name_of_site'}/g;
# new way:
$$hashref{$key} =~ s/%%server_name%%/$ENV{SERVER_NAME}/g;
$$hashref{$key} =~ s/%%http_host%%/$ENV{HTTP_HOST}/g;
$$hashref{$key} =~ s/%%name_of_site%%/$$hashref{name_of_site}/g;
}
}
# pass filename to create and optionally the mode to chmod it to.
# the mode must consist of 1-4 octal digits and must NOT be quoted.
# see "perldoc -f chmod" and "man chmod".
sub create_file_if_DNE
{
my $file = shift;
my $mode = shift;
return if -T $file;
open(NEW,">$file") or die "$0: couldn't create new file $file: $!\n";
close NEW or die "$0: couldn't close $file after creating it: $!\n";
if($mode)
{
chmod($mode,$file) or die "$0: couldn't chmod file \"$file\" with mode \"$mode\": $!\n";
}
}
sub create_dir_if_DNE
{
my $dir = shift;
my $mode = shift;
return if -d $dir;
mkdir($dir,0777) or die "$0: couldn't create dir $dir: $!\n";
if($mode)
{
chmod($mode,$dir) or die "$0: couldn't chmod dir \"$dir\" with mode \"$mode\": $!\n";
}
}
sub send_email
{
my ($to, $from, $subj, $msg, $mimetype, $die_on_error, $attachment_hashref) = @_;
$mimetype = 'text/plain' unless $mimetype;
$die_on_error = $die_on_error eq 'die_on_email_error' ? 1 : 0;
my $do_fork = !$die_on_error; # if we want to die on error, we can't fork, or the die() will go unreported.
$do_fork = 0 if $^O =~ /MSWin32/; # Windows' fork-fu is weak.
# fork here because sending mail can be slow (and can block) sometimes.
# Note: if we don't set $do_fork, perl won't even evaluate the &&'s second
# half, so the fork won't happen, and the else{} will.
my $forkpid = ();
if($do_fork && ($forkpid = fork))
{
# parent
}
else
{
# child
use POSIX;
if($do_fork)
{
defined $forkpid or die "$0: fork error in send_email(): $@\n";
POSIX::setsid() unless $^O =~ /MSWin32/;
close STDOUT;
close STDIN;
}
my $mail_sent_successfully = 0;
if($PREF{smtp_server} =~ /\w/)
{
# Wrap this in an eval{} in case MIME::Lite is missing.
# Then we can have the option of setting $PREF{'disable_all_email'}
# so that the site still functions, sans email.
eval
{
require MIME::Lite;
my $type = ();
if($mimetype)
{
$type = $mimetype;
}
else
{
#my $type = $attachment_hashref ? 'multipart/mixed' : 'text/plain';
$type = $attachment_hashref ? 'multipart/mixed' : 'text/plain; charset=ISO-8859-1; format=flowed';
}
my $mime_msg = MIME::Lite->new(
To => $to,
From => $from,
Subject => $subj,
Type => $type,
Data => $msg
) or sub {
if($die_on_error) { die "$0: error creating MIME body: $!\n"; }
else { warn "$0: error creating MIME body: $!\n"; }
};
if($attachment_hashref)
{
foreach my $key (keys %$attachment_hashref)
{
my $mimetype = $$attachment_hashref{$key}{mimetype}; # like 'application/x-gzip'
my $filename = $$attachment_hashref{$key}{filename};
my $recommended_filename = $$attachment_hashref{$key}{recommended_filename};
$recommended_filename =~ s!^.*(\\|/)!!; # strip off any preceeding path
# Attach the test file
$mime_msg->attach(
Type => $mimetype,
Path => $filename,
Filename => $recommended_filename,
Disposition => 'attachment'
) or sub {
if($die_on_error) { die "$0: error attaching file to email: $!\n"; }
else { warn "$0: error attaching file to email: $!\n"; }
};
}
}
#unless($PREF{smtp_server} =~ /\w/)
#{
# die "$0: can't use MIME::Lite to send email because \$PREF{smtp_server} has not been set...\n";
#}
$PREF{smtp_server} = enc_untaint($PREF{smtp_server});
if($PREF{smtp_auth_username} =~ /\S/ && $PREF{smtp_auth_password} =~ /\S/)
{
eval { MIME::Lite->send('smtp', $PREF{smtp_server}, Timeout=>30, AuthUser=>$PREF{smtp_auth_username}, AuthPass=>$PREF{smtp_auth_password}, Port=>$PREF{smtp_port}); };
}
else
{
eval { MIME::Lite->send('smtp', $PREF{smtp_server}, Timeout=>30, Port=>$PREF{smtp_port}); };
}
if($@)
{
if($die_on_error) { die "$0: MIME::Lite->send failed: $@\n"; }
else { warn "$0: MIME::Lite->send failed: $@\n"; }
}
eval { $mime_msg->send; };
if($@)
{
if($die_on_error) { die "$0: \$mime_msg->send failed: $@\n"; }
else { warn "$0: \$mime_msg->send failed: $@\n"; }
}
else
{
$mail_sent_successfully = 1;
}
if($attachment_hashref)
{
foreach my $key (keys %$attachment_hashref)
{
unlink( $$attachment_hashref{$key}{filename} ) if $$attachment_hashref{$key}{'delete-after-sending'} eq 'yes';
}
}
};
}
my $smtp_error = $@ if $@;
if(-e $PREF{path_to_sendmail} && !$mail_sent_successfully)
{
#warn "$0: error in send_email() while trying to use MIME::Lite; trying sendmail instead.\nError was:\n$@\n";
eval
{
#unless(-e $PREF{path_to_sendmail})
#{
# die "$0: can't use sendmail to send email because \$PREF{path_to_sendmail} ('$PREF{path_to_sendmail}') does not exist.\n";
#}
$PREF{path_to_sendmail} = enc_untaint($PREF{path_to_sendmail}, 'keep_path');
open(SENDMAIL, "|$PREF{path_to_sendmail} -oi -t") or die "$0: Can't fork for sendmail: $!\n";
if($attachment_hashref)
{
print SENDMAIL qq`MIME-Version: 1.0`
. qq`\nFrom: $from`
. qq`\nTo: $to`
. qq`\nSubject: $subj`
. qq`\nContent-Type: multipart/mixed; boundary=encindboundarystring`
. qq`\n`
. qq`\n--encindboundarystring`
. qq`\nContent-Type: ` . ($mimetype ? $mimetype : 'text/plain')
. qq`\n`
. qq`\n$msg`;
foreach my $key (keys %$attachment_hashref)
{
my $mimetype = $$attachment_hashref{$key}{mimetype}; # like 'application/x-gzip'
$mimetype = 'application/octet-stream' unless $mimetype;
my $filename = $$attachment_hashref{$key}{filename};
my $recommended_filename = $$attachment_hashref{$key}{recommended_filename};
$recommended_filename =~ s!^.*(\\|/)!!; # strip off any preceeding path
my $atch = `uuencode $filename $filename`; # UUencode it so we can send it as an attachment
print SENDMAIL qq`\n____________________`
. qq`\nAttachment: $filename:`
. qq`\n`
. qq`\n--encindboundarystring`
. qq`\nContent-Type: $mimetype; name="$filename"`
. qq`\nContent-Transfer-Encoding: x-uuencode`
. qq`\nContent-Disposition: attachment; filename="$recommended_filename"`
. qq`\n`
. qq`\n$atch`
. qq`\n`
. qq`\n--encindboundarystring`;
}
print SENDMAIL qq`\n--encindboundarystring--\n`
}
else # no attachment.
{
print SENDMAIL qq`From: $from`
. qq`\nTo: $to`
. qq`\nSubject: $subj`
. qq`\nContent-Type: $mimetype`
. qq`\n`
. qq`\n$msg`;
}
close(SENDMAIL) or die "$0: sendmail didn't close nicely: $!\n";
};
if($@)
{
#die "$0: Cannot send email; tried MIME::Lite and sendmail but both failed.\n$@\n";
}
else
{
$mail_sent_successfully = 1;
}
}
my $sendmail_error = $@ if $@;
unless($mail_sent_successfully)
{
my $msg = ();
if($smtp_error) { $msg = "$0: couldn't send email: error in send_email() while trying to use MIME::Lite with SMTP server '$PREF{smtp_server}'. Error was: '$@'\n"; }
elsif($sendmail_error) { $msg = "$0: couldn't send email: error in send_email() while trying to use sendmail with path '$PREF{path_to_sendmail}'. Error was: '$@'\n"; }
else { $msg = "$0: couldn't send email: error in send_email(): perhaps you need to adjust \$PREF{smtp_server} (currently '$PREF{smtp_server}') or \$PREF{path_to_sendmail} (currently '$PREF{path_to_sendmail}').\n"; }
if($die_on_error) { die $msg; }
else { warn $msg; }
}
if($do_fork)
{
exit; # exit the child process.
}
}
}
sub enc_untaint
{
my $item = shift;
my $original_item = $item;
my $keep_path = shift;
#print STDERR "enc_untaint($item)\n";
# Regardless of whether we're keeping the path, dots surrounded by slashes are never allowed.
#
#$item =~ s!(^|/|\\)\.+(/|\\|$)!$1!g;
while($item =~ m!((?:^|/|\\)\.+(?:/|\\|$))!)
{
$item =~ s!$1!/!;
}
#print STDERR "removed slashdots: $item\n";
if( $item =~ m!(/|\\)! && !$keep_path)
{
$item =~ s!^.*[/\\]+([^/\\]+)!$1!; # remove any path from the front.
#print STDERR "removed path from front: $item\n";
$item =~ s!^([^/\\]+)[/\\]+!$1!; # ...and the back.
}
$item =~ s![`\*\?\|<>]!!g; # remove some other potentially-unsafe stuff.
$item =~ s![/\\]{2,}!/!g; # condense any multiples.
($item) = ($item =~ /(.*)/); # untaint.
# In case anything slips through, die as a security precaution.
#
die qq`$0: couldn't untaint "$original_item".\n` if $item =~ m![/\\]! && !$keep_path;
die qq`$0: couldn't untaint "$original_item".\n` if $item =~ m!(?:^|/|\\)\.+(?:/|\\|$)!;
die qq`$0: couldn't untaint "$original_item".\n` if $item =~ m!^\.+$!;
die qq`$0: couldn't untaint "$original_item".\n` if $item =~ m!^\s*$!;
#print STDERR "untainted: $item\n\n";
return $item;
}
sub enc_urlencode
{
s/([^\w()'*~!.-])/sprintf '%%%02x', ord $1/eg for @_;
}
sub enc_urldecode
{
# assuming the input really was URL-encoded, then any plus-signs that were originally there
# are now in their hex form, so any plus-signs STILL there were converted from spaces by the
# browser. so they must be converted back BEFORE restoring any original plus-signs from the
# hex codes.
convert_plus_signs_back_to_spaces_in_var_from_GET_method(@_);
s/%([a-fA-F\d]{2})/chr hex $1/eg for @_;
}
sub convert_plus_signs_back_to_spaces_in_var_from_GET_method
{
s/\+/ /g for @_;
}
irdavidnet گفت:parsa space از راد آپلود نیست