#!/usr/bin/perl -w #----------------------------------------------------------------------------------------------------------------- # index view 1.2.1 by Lilia [2004-05-23] #----------------------------------------------------------------------------------------------------------------- # 任意のディレクトリ内にある画像ファイルをアルバム風に一覧表示し # スライドショー風の閲覧も可能にするスクリプト # * 永久無保証・改造推奨 use strict; use CGI::Carp qw(fatalsToBrowser); use Cwd; use File::Find; # not taint-safe use POSIX qw(strftime); use vars qw(%Ini %Qs $img_dir); %Ini = ( Script => q{index view}, Sign => q{script by Lilia(*'-')~}, Dist => q{http://nursery.s8.xrea.com/}, # Plus => q{+}, # or + # ユーザー設定.. #----------------------------------------------------------------------------------------------------------------- # 基本項目 Title => 'index', # ページのタイトル ImgDir => './img', # 画像ディレクトリのパス (カレントディレクトリなら '.') ImgExt => 'jpg|gif|png', # 画像とみなす拡張子 (大・小文字同一視) ViewSub => 0, # 下位ディレクトリにも対応する { 0:無効 / 1:有効 } # 表示関係 VMax => 4, # 横にならぶ画像の個数 HMax => 2, # 縦にならぶ画像の個数 (1ページあたりの最大列数) ImgWidth => 100, # 縮小表示時の画像の幅 ImgHeight => 75, # 縮小表示時の画像の高さ SortType => 2, # { 0:日付の古い順 / 1:新しい順 / 2:名前順 } にならべる # advanced Slideshow => 1, # スライドショー風の表示を可能にする { 0:無効 / 1:有効 / 2:画像が複数ある場合のみ } NoUserSort => 0, # 閲覧者によるファイルのソートを許可しない { 0:無効 / 1:有効 } NameWidth => 0, # ファイル名表示の長さを指定 { n:nバイト(6以上) / 0:自動 } *長いファイル名は短縮される IgnoRE => qr/^$/, # 一覧から除外するファイルの正規表現 (とくに問題なければこのまま) * qr/^\./ は組込み済 # extra NoImgWin => 0, # 画像ファイル名のリンクを別のウィンドウで開かない { 0:無効 / 1:有効 } LiveMode => 0, # prev<->next の代わりに new<->old と表記する { 0:無効 / 1:有効 } # *更新日時または初期設定の順およびその逆順でソートされている場合のみ (NoUserSort 推奨) #-- 以下はスタイルシートやリンク等の追加設定 (不要なら # でコメントアウト可) # body タグ Body => '
', # スタイルシート Style => '', # 設定しなければデフォルトのスタイル (スクリプト末尾の例から選択も可能) # # 記述例 (デフォルト) # Style => q` # body { background-color:#ffffff; color:#333333; font-family:Arial,Tahoma,Helvetica,Verdana,'MS PGothic',Osaka,sans-serif; } # small { font-size:80%; line-height:140%; } # .tall { line-height:200%; } # .note { background-color:transparent; color:#ff0000; } # a:link, a:visited { background-color:transparent; color:#666666; text-decoration:none; } # a:hover,a:active { background-color:transparent; color:#333333; text-decoration:underline; } # a.ex:link, a.ex:visited { background-color:transparent; color:#333333; text-decoration:none; } # a.ex:hover,a.ex:active { background-color:transparent; color:#333333; text-decoration:underline; } # table.index img { border:1px solid #cccccc; margin-bottom:5px; } # table.index img:hover { border-color:#999999; } # /* table.index i.dir:hover { border:1px solid #999999; padding:12px; } */ # `, # ナビゲーション用のタグ # Metas => q` # # `, # 掲示板等へのリンクをつけたければタグで指定 # GoLink => '<< back', # 特殊オプション - for XREA users XreaIns => 0, # xrea.com のバナーを挿入する { 0:無効 / 1:有効 } # ..ここまで #----------------------------------------------------------------------------------------------------------------- # more advanced (test) RelLink => 0, # 画像に関連するURIへのリンクを表示 { 0:無効 / 1:スライドショー表示時のみ / 2:一覧表示時のみ 3:1+2 } N2RLink => sub { # ファイル名から関連URIへのリンクを生成するサブルーチン (RelLink が有効な場合) my($uri,$s) = @_; # ファイル名と形式指定を受け取る my $text = !$s ? '~*rel?' : '~*'; # '一覧表示時のアンカー文字列' : 'スライドショー表示時のアンカー文字列' my $r = 0; # replaced or not #-- # 正規表現をつかった単純な方式の例 (わかりにくいかもしれないけど s/// を x修飾子つきで2行にわけているだけ) # a) 日記 - (s)YYYYMMDD_N.jpg → /diary/YYYYMMDD.html $r = $uri =~ s{^s?(\d{8}).*$} {$text}ix; # or "/diary/?$1" # b) 画像掲示板 - {pre}{time}.jpg → bbs.cgi?date=YMD_HMS # $r = $uri =~ s{^.*?(\d+).*$} # or ^(?:pre)?(\d+).*$ # {'$text'}iex; # その他の例 (RelLink > 1 の場合何度も呼び出されるのであまり重いのはNG) # a) 検索CGI # $uri = qq{$text}; # $r = 1; # b) ヘッダ情報等表示CGI # $uri = qq{$text}; # $r = 1; #-- return $r ? $uri : ''; # 関連URIがあるならそれを、なければ空の値を返す }, ); #----------------------------------------------------------------------------------------------------------------- &xview; exit; # サブルーチン #----------------------------------------------------------------------------------------------------------------- sub xview { # 設定の確認と調整 $Ini{ImgDir} =~ s|/$||; # 末尾に「/」が付いていたら消しておく $Ini{Body} ||= ''; foreach($Ini{Style},$Ini{Metas},$Ini{GoLink},$Ini{Plus}) { $_ = '' unless(defined); } $Ini{Style} = style(uc($1)) if($Ini{Style} =~ /^([\w\-]*)$/); $Ini{IgnoRE} = '(?-xism:^$)' if(!defined $Ini{IgnoRE} || $Ini{IgnoRE} eq '' || $Ini{IgnoRE} eq '(?-xism:)'); $Ini{RelLink} = 0 if(!defined $Ini{RelLink} || $Ini{RelLink} eq ''); $Ini{N2RLink} = sub { return ''; } if(!$Ini{RelLink} || !defined $Ini{N2RLink} || $Ini{N2RLink} eq ''); $Ini{SortKey} = ($Ini{SortType} < 2) ? 'M' : 'N'; # SortType は実はわかりやすい形をとった簡易設定であって... $Ini{SortOrder} = ($Ini{SortType} == 1) ? 'D' : 'A'; # ...ここで本来の設定 SortKey と SortOrder に分解する my($myself) = $0 =~ m|([^/\\]+)$|; my($self_uri) = $ENV{REQUEST_URI} || $ENV{SCRIPT_NAME} || $myself; s/\?.*// foreach($myself,$self_uri); # lose any query part $img_dir = $Ini{ImgDir}; my $title_max = ($Ini{NameWidth} - 3 > 2) ? ($Ini{NameWidth} - 3) : int($Ini{ImgWidth} / 5.5); # 3 for '...' my $target = $Ini{NoImgWin} ? '' : ' target="img"'; my $sort_key = $Ini{SortKey}; my $sort_order = $Ini{SortOrder}; my $no_css = 0; my $page_nr = 1; my $req_dir = ''; my $s_file_nr = 0; my $srch_key = ''; my @info; # クエリ処理 my @current_qs; my $known_q = q[COXDPIQ]; # 後から追加しやすいようにまとめておく # C=N ファイル名 C=M 更新日時 C=S サイズ C=T 種類 # O=A 昇順 O=D 降順 # X=0 スタイルシート除去無効 X=1 スタイルシート除去有効 # D=dirname 下位ディレクトリ # P=n nページ目 # I=n n番目のアイテム *スライドショー表示 # Q=filename ファイル名(の一部) *簡易検索 if($ENV{QUERY_STRING}) { foreach(split(/;/, $ENV{QUERY_STRING})) { next unless(/=.+/); my($name,$value) = split /=/; next unless($name =~ s/^([$known_q]).*$/\u$1/io); # 不明なクエリは受付けない $Qs{$name} = $value; } } # C { N:ファイル名 / M:更新日時 / S:サイズ / T:種類 } $sort_key = $Qs{C} if(!$Ini{NoUserSort} && $Qs{C} && $Qs{C} =~ s/^([NMST]).*$/\u$1/i); push @current_qs, "C=$sort_key" if($sort_key ne $Ini{SortKey}); # O { A:昇順 / D:降順 } $sort_order = $Qs{O} if(!$Ini{NoUserSort} && $Qs{O} && $Qs{O} =~ s/^(A|D).*$/\u$1/i); push @current_qs, "O=$sort_order" if($sort_order ne $Ini{SortOrder}); # X { 0:スタイルシート除去無効 / 1:スタイルシート除去有効 } $no_css = 1 if($Qs{X}); push @current_qs, "X=1" if($no_css != 0); # P { n:nページ目 } $page_nr = $Qs{P} if($Qs{P} && $Qs{P} =~ s/^(\d+).*$/$1/); # D { dirname:下位ディレクトリ } $req_dir = $Qs{D} if($Ini{ViewSub} && exists $Qs{D}); $req_dir =~ s/%([0-9A-Fa-f][0-9A-Fa-f])/pack('H2', $1)/eg; # I { n:n番目のアイテム } * P とは共存しない $s_file_nr = $Qs{I} if($Ini{Slideshow} && $Qs{I} && $Qs{I} =~ s/^(\d+).*$/$1/); # Q { filename:ファイル名(の一部) } if(exists $Qs{Q}) { if(($srch_key = $Qs{Q}) =~ s|^.*?([\w\-\.]+).*$|$1|) { push @current_qs, "Q=$srch_key"; } else { $srch_key = ''; push @info, "! mal-formed QArg, 'Q=filename'."; } } # 下位ディレクトリ内のファイル表示を要求された場合の下処理 my @upper_dirs; if($req_dir ne '') { if($req_dir =~ m|[^\./ ]| && $req_dir !~ m%(?:^|/)\.*(?:/|$)% && -d "$img_dir/$req_dir") { # 有効性をチェック $img_dir = "$img_dir/$req_dir"; push @upper_dirs, '.'; # 初期ディレクトリは後の処理の都合上「.」としておく (ファイルリスト中の他の要素はこの値をとらない) push @upper_dirs, '.' if($req_dir =~ m|/|); # 2段階以上の場合 1段上のディレクトリも同様に } else { $req_dir = ''; push @info, "! mal-formed QArg, 'D=dirname'."; } } s/&/&/g, s/</g, s/>/>/g, s/"/"/g foreach($req_dir); # 一応 push @current_qs, "D=$req_dir" if($req_dir ne ''); my $not_files = @upper_dirs; # 画像ディレクトリを開きファイルのリストを取得 my @files; opendir(DIR, $img_dir) or die("Unable to opendir $img_dir: $!"); foreach(grep(!/^\./, readdir(DIR))) { next if($_ eq $myself || /$Ini{IgnoRE}/o || !(m|[^\./ ]| && -e "$img_dir/$_")); # 無効なファイルを除外 next if(-d _ && !$Ini{ViewSub}); next if(-f _ && !/\.($Ini{ImgExt})$/io); next if($srch_key ne '' && !/\Q$srch_key\E/io); $not_files++ if(-d _); push @files, $_; } closedir(DIR); # ソート my $by_rule = "by_$sort_key$sort_order"; @files = sort $by_rule @files; # FoldersFirst sub folder { (-d "$img_dir/$b") cmp (-d "$img_dir/$a"); } # 昇順 - N:ファイル名 M:更新日時 S:サイズ T:種類 sub NameA { uc($a) cmp uc($b); } # secondary key: C=N,O=A (always) sub by_NA { folder or NameA; } sub by_MA { folder or (-M "$img_dir/$b") <=> (-M "$img_dir/$a") or NameA; } sub by_SA { folder or (-s "$img_dir/$a") <=> (-s "$img_dir/$b") or NameA; } sub by_TA { folder or tof($a) cmp tof($b) or NameA; } # 降順 sub by_ND { folder or uc($b) cmp uc($a); } sub by_MD { folder or (-M "$img_dir/$a") <=> (-M "$img_dir/$b") or NameA; } sub by_SD { folder or (-s "$img_dir/$b") <=> (-s "$img_dir/$a") or NameA; } sub by_TD { folder or tof($b) cmp tof($a) or NameA; } @files = (@upper_dirs,@files); my $all_files = @files; $s_file_nr = 0 unless(defined $files[$s_file_nr - 1] && -f "$img_dir/$files[$s_file_nr - 1]"); push @info, "! mal-formed and/or invalid QArg, 'I=n'." if($Qs{I} && !$s_file_nr); # 無効なスライドショー要求 # 簡易ラベル変更 my $on_mode = !$Ini{LiveMode} ? 0 : ($sort_key eq $Ini{SortKey} && $sort_key ne 'M') ? ($sort_order ne $Ini{SortOrder}) ? 2 : 1 : ($sort_key eq 'M') ? ($sort_order eq 'A') ? 2 : 1 : 0; my %t = !$on_mode ? ( # 通常 prev => 'prev', next => 'next', ) : ( # ライブカメラ等用 prev => 'new', next => 'old', ); ($t{prev},$t{next}) = ($t{next},$t{prev}) if($on_mode == 2); # 逆順 # スタイルシート my $css = $no_css ? qq`` : qq` `; # バナー表示 my($banner,$sbanner,$nobanner,$noembed) = ('','','',''); # $banner:一覧表示時のバナー, $sbanner:スライドショー表示時のバナー ($banner,$nobanner) = (("\n" . <<"_XREA_"),'') if($Ini{XreaIns} && $ENV{SERVER_NAME} && $ENV{SERVER_NAME} ne 'localhost'); # xrea広告 (メイン画面だけの表示でいい) _XREA_ # $noembed = ($ENV{SERVER_NAME} && $ENV{SERVER_NAME} =~ /(?:virtualave|hypermart)\.net/i) ? "[DIR] $dir_title >> |
_DIR_
} else { # ファイル
my $img_info = sizef(-s "$img_dir/$_");
(my $img_title = $_) =~ s/^(.{$title_max}).{4,}$/$1.../o; # LongName...
$img_info = "$_, $img_info" if($img_title ne $_); # ファイル名を短縮した場合はアンカータグの title でフル表示
my $img_src = "$img_dir/$_";
# $img_src =~ s|([^a-z0-9\-_./])|'%' . unpack('H2', $1)|ieg; # URIエスケープ
my $rel_anchor = ($Ini{RelLink} > 1) ? &{$Ini{N2RLink}}($_,1) : '';
s/&/&/g, s/</g, s/>/>/g, s/"/"/g foreach($_,$img_info,$img_title,$img_src);
my($img_link1,$img_link2) = $slide_link
? (qq``,'')
: ('','');
print <<"_IMG_";
$img_link1 $img_title$rel_anchor |
_IMG_
}
$file_nr++;
}
print "