#!/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 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 ad banner -
xrea ad banner
_XREA_ # $noembed = ($ENV{SERVER_NAME} && $ENV{SERVER_NAME} =~ /(?:virtualave|hypermart)\.net/i) ? "\n\n" : ''; # バナー消し (参考) # ヘッダ・フッタ my $header = qq`<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"> <html lang="ja"> <head>$nobanner <meta name="robots" content="NONE"> <meta http-equiv="content-type" content="text/html; charset=shift_jis"> $css`; $banner = $sbanner if($s_file_nr); my $footer = qq`<small class="tall">:: generated by <a href="$Ini{Dist}" title="$Ini{Sign}" class="ex">$Ini{Script}</a>$Ini{Plus} ::<br></small> </div> $banner <br> </body> </html>$noembed`; if($s_file_nr) { # スライドショー表示 push @current_qs, "I=$s_file_nr"; push @info, "! invalid QArg, 'P=n': 'I=$s_file_nr' is set." if($page_nr != 1); my $img_name = $files[$s_file_nr - 1]; my $img_src = "$img_dir/$img_name"; my $img_size = sizef(-s $img_src); # $img_src =~ s|([^a-z0-9\-_./])|'%' . unpack('H2', $1)|ieg; # URIエスケープ s/&/&amp;/g, s/</&lt;/g, s/>/&gt;/g, s/"/&quot;/g foreach($img_name,$img_src); # 一応 my $prev_file = (defined $files[$s_file_nr - 2] && -f "$img_dir/$files[$s_file_nr - 2]") ? $s_file_nr - 1 : 0; my $next_file = (defined $files[$s_file_nr] && -f "$img_dir/$files[$s_file_nr]") ? $s_file_nr + 1 : 0; my $prev_uri_qs = $prev_file ? ("$self_uri?" . xjoin(';', '^I' => "I=$prev_file", @current_qs)) : ''; my $next_uri_qs = $next_file ? ("$self_uri?" . xjoin(';', '^I' => "I=$next_file", @current_qs)) : ''; my $index_uri_qs = ("$self_uri?" . xjoin(';', '^I' => undef, @current_qs)); my($prev_navi,$prev_anchor) = $prev_file ? (qq`\n<link rel="prev" href="$prev_uri_qs" title="$t{prev}">`, qq`<a href="$prev_uri_qs">&lt;&lt; $t{prev}</a>&nbsp;&nbsp; `) : ('','<!-- no prev -->'); my($next_navi,$next_anchor) = $next_file ? (qq`\n<link rel="next" href="$next_uri_qs" title="$t{next}">`, qq`<a href="$next_uri_qs">$t{next} &gt;&gt;</a>`) : ('','<!-- no next -->'); my $opt_query_s = $no_css ? qq`<br>\n<a href="$self_uri?@{[xjoin(';', '^X' => undef, @current_qs)]}" title="Cascading Style Sheets">*CSS on</a>` : qq`<br>\n<a href="$self_uri?@{[xjoin(';', '^X' => 'X=1', @current_qs)]}" title="NO Cascading Style Sheets">*CSS off</a>`; my $rel_anchor = ($Ini{RelLink} && $Ini{RelLink} != 2) ? &{$Ini{N2RLink}}($img_name,0) : ''; $rel_anchor = "&nbsp;&nbsp; \n$rel_anchor" if($rel_anchor); my $err_notes = njoinf(' ', qq`\n<span class="note" title="%s">!%d!</span>`, 1, @info); $err_notes = "<br>$err_notes" if($err_notes); print "Content-Type: text/html; charset=Shift_JIS\n\n", <<"_SLID_"; $header <link rel="index" href="$index_uri_qs" title="index">$prev_navi$next_navi <title>$s_file_nr/$all_files $img_name, $img_size</title> </head> $Ini{Body} <div align="center"> <small> $prev_anchor <a href="$index_uri_qs">index</a>&nbsp;&nbsp; $next_anchor$rel_anchor$err_notes </small> <hr> @{[$next_navi ? qq(<a href="$next_uri_qs" title="$t{next}">) : qq(<a href="$index_uri_qs" title="index">) ]}<img src="$img_src" border=0 alt="$img_name"></a> <hr> <small> $prev_anchor <a href="$index_uri_qs">index</a>&nbsp;&nbsp; $next_anchor$rel_anchor$opt_query_s </small><br> $footer _SLID_ return; # スライドショー表示の場合はこれで処理終了 } my $p_item_max = $Ini{VMax} * $Ini{HMax}; # 1ページの表示可能数 = 横 x 縦 my $all_pages = ($all_files / $p_item_max) || 1; # 全部で何ページか = 全画像数 ÷ 1ページの表示可能数 $all_pages = ($all_pages == int($all_pages)) ? $all_pages : int($all_pages + 1); # 余りの分で+1ページ if($page_nr > $all_pages || $page_nr <= 0) { # ページ数を超える要求・0ページ以下の要求は無効 $page_nr = 1; push @info, "! mal-formed QArg, 'P=n'."; } push @current_qs, "P=$page_nr" if($page_nr > 1); my $p_end = $p_item_max * $page_nr; # このページには何番目のアイテムまでを表示 $p_end = $all_files if($p_end > $all_files); my $p_start = $p_end ? ($p_item_max * ($page_nr - 1) + 1) : 0; # 何番目から (アイテムがなければ 0 になる) my($page_link,$head_navi,$bottom_navi) = ('','',''); if($all_pages > 1) { # 複数ページにわたるとき my($prev_pages,$next_pages) = ('',''); my $prev_remain = $page_nr - 1; # このページの前に何ページあるか my $next_remain = $all_pages - $page_nr; # このページの後に何ページあるか while($prev_remain > 0) { # 先行ページへのリンク 例: $page_nr = 4 … 3ページある -> 3, 2, 1 $prev_pages = qq`<a href="$self_uri?@{[xjoin(';', '^P' => "P=$prev_remain", @current_qs)]}">$prev_remain</a>&nbsp;&nbsp;$prev_pages`; $prev_remain--; } while($next_remain > 0) { # 後続ページへのリンク 例: $page_nr = 4 … 3ページある -> 7, 6, 5 $next_pages = qq`&nbsp;&nbsp;<a href="$self_uri?@{[xjoin(';', '^P' => ('P=' . ($next_remain + $page_nr)), @current_qs)]}">@{[$next_remain + $page_nr]}</a>$next_pages`; $next_remain--; } # ページ上部に表示する各ページへのリンク (先行_現在_後続) $page_link = qq`<br>\n\n<small class="tall">$prev_pages<b>$page_nr</b>$next_pages</small>`; # ページ下部に表示する前後ページへのリンク およびヘッダ内のナビゲーション my $prev_uri_qs = ($page_nr - 1 > 0) ? ("$self_uri?" . xjoin(';', '^P' => ('P=' . ($page_nr - 1)), @current_qs)) : ''; my $next_uri_qs = ($page_nr + 1 <= $all_pages) ? ("$self_uri?" . xjoin(';', '^P' => ('P=' . ($page_nr + 1)), @current_qs)) : ''; my($prev_navi,$prev_link) = $prev_uri_qs ? (qq`\n<link rel="prev" href="$prev_uri_qs" title="$t{prev}">`, qq`<a href="$prev_uri_qs">$t{prev} &lt;&lt;</a>&nbsp;&nbsp;`) : ('','<!-- no prev -->'); my($next_navi,$next_link) = $next_uri_qs ? (qq`\n<link rel="next" href="$next_uri_qs" title="$t{next}">`, qq`&nbsp;&nbsp;<a href="$next_uri_qs">&gt;&gt; $t{next}</a>`) : ('','<!-- no next -->'); $head_navi = $prev_navi . $next_navi; $bottom_navi = qq`\n<small>$prev_link$p_start - $p_end of $all_files$next_link</small><br>\n`; } # ソートとスタイルシート切替の機能を提供するリンク my $opt_query = $all_files ? ($all_files >= 2) ? "($all_files items)&nbsp;" : "($all_files item)&nbsp;" : '(no item)&nbsp;&nbsp;'; if($all_files >= 2 && !$Ini{NoUserSort}) { # ソート用リンクは複数ある場合だけ表示 my(%qs,%in,%sw); # 昇順が基本 ($qs{$_},$in{$_},$sw{$_}) = ("C=$_;O=A",'ascending', '+') foreach qw(N M S T); # 現在昇順でソートされている項目のみ降順に反転 ($qs{$sort_key},$in{$sort_key},$sw{$sort_key}) = ("C=$sort_key;O=D",'descending','-') if($sort_order eq 'A'); $opt_query.= qq` <a href="$self_uri?@{[xjoin(';', '^(?:C|O|P)' => "$qs{N}", @current_qs)]}" title="sort by name ($in{N})">*name$sw{N}</a> <a href="$self_uri?@{[xjoin(';', '^(?:C|O|P)' => "$qs{M}", @current_qs)]}" title="sort by date ($in{M})">*date$sw{M}</a> <a href="$self_uri?@{[xjoin(';', '^(?:C|O|P)' => "$qs{S}", @current_qs)]}" title="sort by size ($in{S})">*size$sw{S}</a> <a href="$self_uri?@{[xjoin(';', '^(?:C|O|P)' => "$qs{T}", @current_qs)]}" title="sort by type ($in{T})">*type$sw{T}</a>`; } $opt_query.= $no_css ? qq` \n<a href="$self_uri?@{[xjoin(';', '^X' => undef, @current_qs)]}" title="Cascading Style Sheets">*CSS on</a>` : qq` \n<a href="$self_uri?@{[xjoin(';', '^X' => 'X=1', @current_qs)]}" title="NO Cascading Style Sheets">*CSS off</a>`; my $p_img_dir = $img_dir; #「index of 〜」の表示用 if($p_img_dir eq '.') { # カレントディレクトリの場合 できればパスの表示を少し工夫 $p_img_dir = cwd || getcwd || ''; $p_img_dir = $1 if($p_img_dir eq '' && $ENV{SCRIPT_NAME} && $ENV{SCRIPT_NAME} =~ m|^(.*)/[^/]+$|); $p_img_dir =~ s/^\QENV{DOCUMENT_ROOT}\E//i if($ENV{DOCUMENT_ROOT}); $p_img_dir =~ s|^/?|/|; $p_img_dir =~ s|/?$||; $p_img_dir =~ s|^.*/|../|; $p_img_dir = '/' if($p_img_dir eq ''); } my $slide_link = 1 if($Ini{Slideshow} && $all_files - $not_files >= $Ini{Slideshow}); { # スライドショー用のリンク my $first_file = (defined $files[$not_files] && -f "$img_dir/$files[$not_files]") ? $not_files + 1 : 0; my $first_uri_qs = $first_file ? ("$self_uri?" . xjoin(';', '^(?:I|P)' => "I=$first_file", @current_qs)) : ''; $Ini{GoLink}.= $slide_link ? qq`&nbsp;&nbsp; \n<a href="$first_uri_qs">#slideshow</a>` : '<!-- no slideshow -->'; $Ini{GoLink} = "\n<small>$Ini{GoLink}</small><br>\n"; } my $err_notes = njoinf(' ', qq`\n<span class="note" title="%s">!%d!</span>`, 1, @info); # 一覧表示 print "Content-Type: text/html; charset=Shift_JIS\n\n", <<"_HTML_"; $header$Ini{Metas}$head_navi <title>$Ini{Title}</title> </head> $Ini{Body} $Ini{GoLink} <div align="center"> index of <a href="$img_dir/" class="ex">$p_img_dir</a>&nbsp;<small>@{[ ($srch_key ne '') ? (qq`<a href="$self_uri?` . xjoin(';', '^Q' => undef, @current_qs) . qq`" title="clear">[Q:$srch_key]</a>&nbsp;`) : '' ]}$opt_query$err_notes</small>$page_link<br><br> <table align="center" border=0 cellpadding=8 summary="images" class="index"> _HTML_ my $img_remain = @files ? 1 : 0; my $h_nr = 0; while(@files) { last if($img_remain <= 0 || $h_nr == $Ini{HMax}); # 表示する画像がなくなった or ページの最大列数を超えたらやめる my $v_start = ($Ini{VMax} * $h_nr) + ($p_item_max * ($page_nr - 1)); # 横にならぶ個数 x 現在何列目か (6x0, 6x1, 6x2, ...) + 先行ページ分 my $v_end = $v_start + $Ini{VMax} - 1; # 0〜5, 6〜11, 12〜17, ... というふうにしたいので -1 $v_end = $#files if($v_end > $#files); print "<tr>\n"; my $file_nr = $v_start + 1; foreach(@files[$v_start .. $v_end]) { # 1列分ずつ出力 last unless($_); if(-d "$img_dir/$_") { # ディレクトリ my($dir_label,$dir_title,$dir_path,$dir_qs) = ('sub',"$_/","$img_dir/$_","D=$_"); if($_ eq '.' && $file_nr == 1) { # 初期ディレクトリ ($dir_label,$dir_title,$dir_path,$dir_qs) = ('base','TOP',$Ini{ImgDir},''); } elsif($_ eq '.' && $file_nr == 2) { # 親ディレクトリ (of $req_dir) my($p_dir) = $req_dir =~ m|^(.+)/[^/]+$|; ($dir_label,$dir_title,$dir_path,$dir_qs) = ('parent','UP',"$Ini{ImgDir}/$p_dir","D=$p_dir"); # 'UP' or '../' } elsif($req_dir ne '') { # 現在既にサブディレクトリを開いている状態 $dir_qs = "D=$req_dir/$_"; } my $dir_info = ''; my $get_dirinfo = 1; # 無効可 if($get_dirinfo) { my($indir_dirs,$indir_files,$dir_size) = (0,0,0); find(sub { if(-f) { $dir_size += -s; $indir_files++; } elsif(-d) { $indir_dirs++; } }, $dir_path); $dir_info = " (d=$indir_dirs, f=$indir_files, " . sizef($dir_size) . ")"; } print <<"_DIR_"; <td align="center" width=$Ini{ImgWidth} height=$Ini{ImgHeight}><i class="dir" title="$file_nr/$all_files$dir_info">[DIR]</i><br><br> <small><a href="$dir_path/" title="OPEN $dir_label directory">$dir_title</a> <a href="$self_uri?@{[xjoin(';', '^(?:D|P)' => ($dir_qs ? $dir_qs : undef), @current_qs)]}" title="VIEW $dir_label directory">&gt;&gt;</a></small></td> _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/&/&amp;/g, s/</&lt;/g, s/>/&gt;/g, s/"/&quot;/g foreach($_,$img_info,$img_title,$img_src); my($img_link1,$img_link2) = $slide_link ? (qq`<a href="$self_uri?@{[xjoin(';', '^(?:I|P)' => "I=$file_nr", @current_qs)]}" title="slideshow $file_nr/$all_files">`,'</a>') : ('',''); print <<"_IMG_"; <td align="center">$img_link1<img src="$img_src" width=$Ini{ImgWidth} height=$Ini{ImgHeight} border=1 alt="$file_nr/$all_files">$img_link2<br> <small><a href="$img_dir/$_" title="$img_info"$target>$img_title</a>$rel_anchor</small></td> _IMG_ } $file_nr++; } print "</tr>\n"; $img_remain = $#files - $v_end; # 残り画像数 = 全画像数 - 表示した分 $h_nr++; } print <<"_HTML_"; </table><br> $bottom_navi $footer _HTML_ } # xview end sub tof { my $type = shift; return '' if(!defined $type || $type !~ /\.(.*)$/); $type = uc($1); return $type; } # tof end sub xjoin { # $single_str = xjoin($", '^unwanted$' => 'newvalue', @array_or_LIST); my $s = shift; my $x = shift || '^$'; my $new = shift; return (defined $new) ? join($s, grep(!/$x/, @_),$new) : join($s, grep(!/$x/, @_)); } # xjoin end sub njoinf { # $single_str = njoinf($", "ex %d: %s<br>\n", $[, @array_or_LIST); my($s,$f,$nr,@list) = @_; my $str = ''; my $r = 1 if($f =~ /.*%s.*%d/); foreach(@list) { $str.= $s if($str ne ''); $str.= $r ? sprintf($f, $_,$nr) : sprintf($f, $nr,$_); $nr++; } return $str; } # njoinf end sub sizef { my $size = shift or return 0; my($gb,$mb,$kb) = ($size / 1073741824,$size / 1048576,$size / 1024); $size = ($gb >= 100) ? sprintf("%.0fGB", $gb) : ($gb >= 10) ? sprintf("%.1fGB", $gb) : ($mb >= 1000) ? sprintf("%.2fGB", $gb) : ($mb >= 100) ? sprintf("%.0fMB", $mb) : ($mb >= 10) ? sprintf("%.1fMB", $mb) : ($kb >= 1000) ? sprintf("%.2fMB", $mb) : ($kb >= 100) ? sprintf("%.0fKB", $kb) : ($kb >= 10) ? sprintf("%.1fKB", $kb) : sprintf("%.2fKB", $kb); return $size; } # sizef end sub style { # おまけ my %CSS = ( # キーは大文字で DEFAULT => 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; } */ `, LITE => q` body { background-color:#f0f0f0; 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:#2080a0; } a:link,a:visited { background-color:transparent; color:#666666; text-decoration:none; } a:hover { background-color:transparent; color:#1775a2; text-decoration:underline; } a:active { background-color:transparent; color:#cc0000; 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:#1775a2; text-decoration:underline; } table.index img { border:1px solid #888888; margin-bottom:5px; } table.index img:hover { border-color:#666666; } /* table.index i.dir:hover { border:1px solid #888888; padding:12px; } */ `, TAIYAKI => q` body { background-color:#333333; color:#d0d0d0; 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:#ff69b4; } a:link,a:visited { background-color:transparent; color:#d0d0d0; text-decoration:none; } a:hover { background-color:transparent; color:#d0d0d0; text-decoration:underline; } a:active { background-color:transparent; color:#cc0000; text-decoration:underline; } table.index img { border:1px solid #d0d0d0; margin-bottom:5px; } /* table.index i.dir:hover { border:1px solid #d0d0d0; padding:12px; } */ `, STRANGE => q` body { background-color:#004040; color:#ffffff; 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:#eeffee; text-decoration:none; } a:hover,a:active { background-color:transparent; color:#ff0000; text-decoration:underline; } a.ex:link, a.ex:visited { background-color:transparent; color:#ffffff; text-decoration:none; } a.ex:hover,a.ex:active { background-color:transparent; color:#dddddd; text-decoration:underline; } table.index img { border:1px solid #dddddd; margin-bottom:5px; } table.index img:hover { border-color:#eeffee; } /* table.index i.dir:hover { border:1px solid #eeffee; padding:12px; } */ `, NAZO => q` body { background-color:black; color:red; 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:red; } a:link,a:visited { background-color:transparent; color:green; text-decoration:none; } a:hover { background-color:transparent; color:green; text-decoration:underline; } a:active { background-color:transparent; color:green; text-decoration:underline; } a.ex:link, a.ex:visited { background-color:transparent; color:red; text-decoration:none; } a.ex:hover,a.ex:active { background-color:transparent; color:green; text-decoration:underline; } table.index img { border:1px solid red; margin-bottom:5px; } table.index img:hover { border-color:green; } /* table.index i.dir:hover { border:1px solid red; padding:12px; } */ `, # 自由に追加 CUSTOM => q` body { background-color:#ffffff; color:#333333; } small { font-size:80%; } /* etc. */ `, ); my $s = shift; return (defined $s && exists $CSS{$s}) ? $CSS{$s} : $CSS{DEFAULT}; } # style end # Script END