Приглашаем посетить
Соловьев (solovyev.lit-info.ru)

File Seek

#!/usr/local/bin/perl

############################################################################
#                                                                          #
# FileSeek                          Version 1.5                            #
# Written by Craig Patchett         craig@patchett.com                     #
# Created 7/25/96                   Last Modified 3/14/97                  #
#                                                                          #
# Copyright 1997 Craig Patchett & Matthew Wright.  All Rights Reserved.    #
# This program is part of The CGI/Perl Cookbook from John Wiley & Sons.    #
# License to use this program or install it on a server (in original or    #
# modified form) is granted only to those who have purchased a copy of The #
# CGI/Perl Cookbook. (This notice must remain as part of the source code.) #
#                                                                          #
############################################################################


############################################################################
# Define configuration constants                                           #
############################################################################

# $ROOT_DIR is the full path to the root directory that FileSeek will look
# for files in. (Note that it should end with a directory delimiter.)

$ROOT_DIR = '/home/web/downloads/';

# $ROOT_URL is the URL of the directory specified by $ROOT_DIR

$ROOT_URL = 'http://www.domain.com/downloads';

# $ROOT_NAME is the name of the root directory that will be used within the
# program.

$ROOT_NAME = 'Downloads';

# $ICON_DIR is relative path from your server's root directory where the 
# icons for the different file types will be kept. (Note that it should end 
# with a forward slash.)

$ICON_DIR = '/fileseek/icons/';

# %TYPES matches file types to the corresponding icon files. With the
# exception of 'directory' and 'binary' default file types, each file
# type corresponds to a filename extension.

%TYPES = ('parent',    $ICON_DIR . 'parent.gif',
          'directory', $ICON_DIR . 'directory.gif',
          'binary',    $ICON_DIR . 'binary.gif',
          'txt',       $ICON_DIR . 'text.gif',
          'gif',       $ICON_DIR . 'graphic.gif',
          'jpg',       $ICON_DIR . 'graphic.gif',
          'jpeg',      $ICON_DIR . 'graphic.gif',
          'htm',       $ICON_DIR . 'html.gif',
          'html',      $ICON_DIR . 'html.gif',
          'pdf',       $ICON_DIR . 'pdf.gif');

# $ALLOWED_DIR is the full path to the root directory that any files
# specified by the user must be in (e.g., template files). (Note that 
# it should include a directory delimiter at the end.)

$ALLOWED_DIR = '/home/web/fileseek/';

# $DATE_FORMAT holds the &format_date() format for the file mod date & time

$DATE_FORMAT = '<wday>, <mon> <d>, <year>, <h>:<0n> <AP>';

# $PROGRAM_URL is the URL of this program

$PROGRAM_URL = 'http://www.domain.com/cgi-bin/fileseek.cgi';

# $ERROR_PAGE is the error page template that will be used by the error
# subroutine.

$ERROR_PAGE = "/home/web/error_page.html";

# $REQUIRE_DIR is the directory in which all of your required files are
# placed.  On most systems, if you leave the required files in the same
# directory as the CGI program, you can leave this variable blank.  
# Otherwise, if you move the required files to another directory, specify
# the full or relative path here.

$REQUIRE_DIR = 'require';


############################################################################
# Get required subroutines which need to be included.                      #
############################################################################

# Push $REQUIRE_DIR onto the @INC array for include file directories
# and list required files.

push(@INC, $REQUIRE_DIR) if $REQUIRE_DIR;

require 'formdate.pl';
require 'template.pl';
require 'error.pl';


############################################################################
# Initialize other constants                                               #
############################################################################

@DAYS = ('Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 
         'Saturday');
@MONTHS = ('January', 'February', 'March', 'April', 'May', 'June', 'July',
           'August', 'September', 'October', 'November', 'December');
$DAY_SECS = 24 * 60 * 60;

if ($ENV{'QUERY_STRING'} !~ /sort=\d/ && $ENV{'QUERY_STRING'}) {
    $adjust = '&' . $ENV{'QUERY_STRING'};
}
$NAME_TITLE = "<A HREF=\"$PROGRAM_URL?$`sort=0$'$adjust\">Name</A>";
$SIZE_TITLE = "<A HREF=\"$PROGRAM_URL?$`sort=1$'$adjust\">Size</A>";
$DATE_TITLE = "<A HREF=\"$PROGRAM_URL?$`sort=2$'$adjust\">Last Modified</A>";


############################################################################
# Parse query string                                                       #
############################################################################

(@args) = split(/&/, $ENV{'QUERY_STRING'});
foreach $arg (@args) {
    ($arg, $value) = split(/=/, $arg);
    $value =~ tr/+/ /;
    $value =~ s/%([\dA-Fa-f][\dA-Fa-f])/pack("C", hex($1))/eg;
    if (($arg eq 'query') && ($value ne '')) { $ARGS{$arg} = '.*' }
    else { $ARGS{$arg} = $value }
}
$sort_order = ($ARGS{'sort'} || 0);
$directory = $ARGS{'dir'};
$VAR{'query'} = $ARGS{'query'} if $ARGS{'query'};
$VAR{'root_name'} = $ROOT_NAME;


############################################################################
# Perform security and validity checks on directories and files            #
############################################################################

# Set the directory delimiter based on $ROOT_DIR and make sure the 
# different directory variables end or don't end with a delimiter as 
# called for.

$DD = substr($ROOT_DIR, -1);
if ($DD !~ /[\/:]/) { 
    &error("\$ICON_DIR must end with a directory delimiter.");
}
if ($ALLOWED_DIR !~ /$DD$/) { $ALLOWED_DIR .= $DD }
if ($directory && (substr($directory, 0, 1) ne $DD)) {
    $directory = "$DD$directory";
}
$directory =~ s/$DD$//g;
$VAR{'directory'} = $directory if $directory;
$VAR{'full_dir'} = "$ROOT_NAME$directory";

# Change to root in case an invalid directory was specified

if (!$ROOT_DIR) { &error('$ROOT_DIR has not been defined.') }
if (!(-d $ROOT_DIR)) { &error("$ROOT_DIR is not a valid directory ($!).") }
if (!(-r $ROOT_DIR)) { &error("$ROOT_DIR is not readable ($!).") }
chdir($ROOT_DIR);

# Make sure they're not trying to access an invalid directory

if ($directory =~ /$DD\.\./) { $directory = '' }
$ARGS{'head'} =~ s/(^$ALLOWED_DIR)|(^$DD)|(\.\.($DD|$))//g;
$ARGS{'foot'} =~ s/(^$ALLOWED_DIR)|(^$DD)|(\.\.($DD|$))//g;


############################################################################
# Perform search or get directory listing                                  #
############################################################################

if ($ARGS{'query'}) {
    $VAR{'page_title'} = "Search of $ROOT_NAME$directory for \"$ARGS{'query'}\"";

    # Recursively search directory
    
    &search("$ROOT_DIR$directory", '', $ARGS{'query'});
    chdir("$ROOT_DIR$directory");
}
else {
    $VAR{'page_title'} = "Directory of $ROOT_NAME$directory";

    # Read list of files
    
    chdir("$ROOT_DIR$directory");
    @link_files = @files = <*>;
}
$num_items = @files;


############################################################################
# Get file information                                                     #
############################################################################

$count = 0;
foreach $file (@link_files) {
    $filename = $files[$count];
    $directory{$filename} = -d $file;                            # Directory flag
    if (!$directory{$filename}) { $size{$filename} = -s $file }  # Size (in bytes)
    $modify{$filename} = $^T - int((-M $file) * $DAY_SECS);      # Modification date
    $readable{$filename} = -r $file;                             # Read permission
    $full_path{$filename} = $file;                               # Path from dir
    
    # Determine file type
    
    $_ = $file;
    tr/A-Z/a-z/;
    if ((/\.([^.]+)$/) && $TYPES{$1}) { $type{$filename} = $1 }  # Use extension
    elsif (-B $file) { $type{$filename} = 'binary' }             # Check for binary
    else { $type{$filename} = 'txt' }                            # Otherwise text
    ++$count;
}


############################################################################
# Sort files                                                               #
############################################################################

if ($sort_order == 1) {
    @sorted_files = sort by_size @files;
    $SIZE_TITLE = "<B>Size</B>";
}
elsif ($sort_order == 2) { 
    @sorted_files = sort by_date @files;
    $DATE_TITLE = "<B>Last Modified</B>"
}
else { 
    @sorted_files = sort by_name @files;
    $NAME_TITLE = "<B>Name</B>";
}


############################################################################
# Generate the HTML page                                                   #
############################################################################

# Generate the arguments for links back to the program

if ($ARGS{'sort'}) { $sort_arg = "sort=$sort_order&"} else { $sort_arg = '' }
if ($ARGS{'head'}) {
    $temp_arg .= "head=$ARGS{'head'}&";
}
if ($ARGS{'foot'}) {
    $temp_arg .= "foot=$ARGS{'foot'}&";
}

# Generate the HTML header

print "Content-type: text/html\n\n";

# Insert the page header if specified

if ($ARGS{'head'}) {
    if (!&parse_template("$ALLOWED_DIR$ARGS{'head'}", *STDOUT)) {
        &error($Error_Message, '', '', 1);
    }
}
else {
    print <<END_HTML;
<HTML>
   <HEAD>
      <TITLE>$VAR{'page_title'}</TITLE>
   </HEAD>
   <BODY BGCOLOR="#FFFFFF">
END_HTML
}

# Generate the directory header

print <<END_HTML;
      <FORM ACTION="$PROGRAM_URL" METHOD=GET>
         Enter your single word search here: 
         <INPUT SIZE=20 TYPE=TEXT NAME="query"> 
         <INPUT TYPE="submit" VALUE="Search"> 
         <INPUT TYPE="hidden" NAME="sort" VALUE="$sort_order">
         <INPUT TYPE="hidden" NAME="dir" VALUE="$directory">
         <INPUT TYPE="hidden" NAME="head" VALUE="$ARGS{'head'}">
         <INPUT TYPE="hidden" NAME="foot" VALUE="$ARGS{'foot'}">
      </FORM>
      <P>
      <B>$VAR{'page_title'}:</B>
      <P>
      <TABLE BORDER=0 CELLPADDING=0 WIDTH=100%>
         <TR>
            <TD HEIGHT=17 ALIGN=CENTER WIDTH=50 NOWRAP>
               $num_items items
            </TD><TD WIDTH=5 ALIGN=LEFT>
                      
            </TD><TD ALIGN=LEFT>
               $NAME_TITLE
            </TD><TD ALIGN=RIGHT WIDTH=100>
               $SIZE_TITLE
            </TD><TD WIDTH=5 ALIGN=LEFT>
                      
            </TD><TD ALIGN=LEFT WIDTH=900>
               $DATE_TITLE      
            </TD></TR>
         <TR>
            <TD COLSPAN=6 HEIGHT=10>
               <HR>
            </TD></TR>
END_HTML

# Generate the link to the parent directory if appropriate

if ($directory && !$ARGS{'query'}) {
    $parent = substr($directory, 0, rindex($directory, $DD));
    $file_link = "<A HREF=\"$PROGRAM_URL?$sort_arg$temp_arg";
    $file_link .= "dir=$parent\">\n";
    $file = '<I>Parent Directory</I>';
    $link_close = '</A>';
    
    print <<END_HTML;
         <TR>
            <TD HEIGHT=17 ALIGN=CENTER>
               $file_link
               <IMG SRC="$TYPES{'parent'}" WIDTH=16 HEIGHT=16 BORDER=0>$link_close
            </TD><TD ALIGN=RIGHT>
                
            </TD><TD ALIGN=LEFT>
               $file_link$file$link_close
            </TD><TD ALIGN=RIGHT>
                
            </TD><TD WIDTH=5 ALIGN=LEFT>
                
            </TD><TD ALIGN=LEFT>
                
            </TD></TR>
END_HTML
}

# Generate the directory listing

foreach $file (@sorted_files) {
    
    # If the file is a directory, link back to the program
    
    if ($directory{$file}) {
        $file_link = "<A HREF=\"$PROGRAM_URL?$sort_arg$temp_arg";
        $file_link .= "dir=$directory$full_path{$file}\">";
        $image_link = $TYPES{'directory'};
        $file_size = '-';
    }
    else {
    
        # Otherwise link to the file and format the file size
    
        $file_link = "<A HREF=\"$ROOT_URL$directory$DD$full_path{$file}\">";
        $image_link = $TYPES{$type{$file}};
        $file_size = &size_format($size{$file});
    }
    
    # Remove the link if the file isn't readable by the user
    
    if (!$readable{$file}) { $file_link = $link_close = '' }
    else { $link_close = '</A>' }
    
    # Calculate the modification date
    
    $mod_date = &format_date($modify{$file}, $DATE_FORMAT);
    
    # Print the file information
    
    print <<END_HTML;
         <TR>
            <TD HEIGHT=17 ALIGN=CENTER>
               $file_link
               <IMG SRC="$image_link" WIDTH=16 HEIGHT=16 BORDER=0>$link_close
            </TD><TD ALIGN=RIGHT>
                
            </TD><TD ALIGN=LEFT>
               $file_link$file$link_close
            </TD><TD ALIGN=RIGHT>
               $file_size
            </TD><TD WIDTH=5 ALIGN=LEFT>
                
            </TD><TD ALIGN=LEFT>
               $mod_date
            </TD></TR>
END_HTML
}
print "      </TABLE>\n      <HR>\n";

# Insert the page footer if specified

if ($ARGS{'foot'}) {
    if (!&parse_template("$ALLOWED_DIR$ARGS{'foot'}", *STDOUT)) {
        &error($Error_Message, '', '', 1);
    }
}
else { print "   </BODY>\n</HTML>" }


############################################################################
# Search subroutine                                                        #
############################################################################

sub search {
    
    # Initialize
    
    local($SEARCH_ROOT, $search_dir, $search_query) = @_;
    chdir("$SEARCH_ROOT$DD$search_dir");
    local(@filenames) = <*>;
    local($file);
    
    # Scan directory & subdirectories
    
    foreach $file (@filenames) {
        if (-d $file && -r $file) { 
            if ($search_dir) { 
                &search($SEARCH_ROOT, "$search_dir$DD$file", $search_query);
            }
            else { &search($SEARCH_ROOT, $file, $search_query) }
            chdir("$SEARCH_ROOT$DD$search_dir");
        }
        if ($file =~ /$search_query/i) {
            if ($search_dir) { push(@link_files, "$search_dir$DD$file") }
            else { push(@link_files, $file) }
            push(@files, $file);
        }
    }
}
    

############################################################################
# File size format subroutine                                              #
############################################################################

sub size_format {

    # Initialize
    
    local($size) = $_[0];
    
    # Format
    
    if ($size < 1024) { return("1K") }
    elsif ($size < 1048576) { return(int($size/1024 + .5) . "K") }
    else { return((int(10 * $size/1048576 + .5) / 10) . " MB") }
}


############################################################################
# Custom sort subroutines                                                  #
############################################################################

sub by_size { 
    $a2 = $a;
    $a2 =~ tr/A-Z/a-z/;
    $b2 = $b;
    $b2 =~ tr/A-Z/a-z/;
    ($size{$b} <=> $size{$a}) || ($a2 cmp $b2) || ($modify{$b} <=> $modify{$a});
}

sub by_date { 
    $a2 = $a;
    $a2 =~ tr/A-Z/a-z/;
    $b2 = $b;
    $b2 =~ tr/A-Z/a-z/;
    ($modify{$b} <=> $modify{$a}) || ($a2 cmp $b2) || ($size{$b} <=> $size{$a});
}

sub by_name { 
    $a2 = $a;
    $a2 =~ tr/A-Z/a-z/;
    $b2 = $b;
    $b2 =~ tr/A-Z/a-z/;
    ($a2 cmp $b2) || ($a cmp $b);
}