#! /usr/local/bin/ruby -EUTF-8
# coding: UTF-8
require 'cgi'
require 'resolv'
require 'nkf'
#--- デザイン ---------------------------------------------------------
PAGE_TITLE = "■ページトップに表示するタイトル■"
TITLE_FONT_COLOR = "darkslategray" #2f4f4f
BODY_TEXT_COLOR = "black" #000000
BODY_BGCOLOR = "lightcyan" #e0ffff
#--- 供用設定 ---------------------------------------------------------
USER_ID = "■ユーザーID■"
USER_PWD = "■パスワード■"
#--- 個別設置環境 -----------------------------------------------------
USER_DIR = "■設置先ディレクトリ■"
SITE_TITLE = "■ブラウザに表示するタイトル■(#{ USER_DIR })"
HOME_PAGE = "https://■設置先サーバー■/#{ USER_DIR }/"
#--- ファイル構成 -----------------------------------------------------
FILES_DIR = "files"
LIST_FILE = "list.txt"
UPLOAD_CGI = "upload.cgi"
INDEX_CGI = "index.cgi"
#--- ローマ数字に対応するアルファベット -------------------------------
ROMAN_ASCII_TABLE = {
"\u2160" =>"I", "\u2161" =>"II", "\u2162" =>"III", "\u2163" =>"IV",
"\u2164" =>"V", "\u2165" =>"VI", "\u2166" =>"VII", "\u2167" =>"VIII",
"\u2168" =>"IX", "\u2169" =>"X", "\u216A" =>"XI", "\u216B" =>"XII",
"\u216C" =>"L", "\u216D" =>"C", "\u216E" =>"D", "\u216F" =>"M"
}
#--- ローマ数字の値 ---------------------------------------------------
ROMAN_ARABIC_TABLE = {
"I" =>"+1", "V" =>"+5", "X" =>"+10", "L" => "+50",
"C" =>"+100", "D" =>"+500", "M" =>"+1000"
}
#--- 漢数字の数値化モジュール -----------------------------------------------------------------------------
#「京」が万進で「正」しいかは「不可思議」であり命数なのかも文脈依存なので、「京」以上には対応しない。
REG_NUMERICAL = "[0-9〇零一壱弌壹二弐弍貳貮三参參四肆五伍六陸七漆質八捌九玖十拾廿念卅丗百佰陌千仟阡万萬億兆"
REG_NUMERICAL << "\u4989\u5344\u534C\u53C1\u53C4\u5EFE\u5F0E\u67D2\u8D30\u9646]+"
module StringEx
refine String do
def value
upper_position = 0 #確定中数 10000~。(万進法の部分。万未満は中数素材、命数素材、更新素材で別管理)
lower_position = 0 #確定命数 10~9990。未確定の中数素材。(十未満は命数素材、更新素材で別管理)
decimal_number = 0 #確定記数。10未満なら未確定の命数素材。10以上でも記数による未確定の中数素材かも。
numeral = 0 #数値化した数字。更新素材。
self.chars {|c|
case c
when "兆" #以下3数詞により命数が確定し中数が更新される。
numeral = 1000000000000
when "億"
numeral = 100000000
when "万", "萬"
numeral = 10000
when "千", "仟", "阡" #以下6数詞により命数が確定し中数素材が更新される。
numeral = 1000
when "百", "佰", "陌"
numeral = 100
when "\u534C" #以下3数詞(40・30・20)に先行記数があれば積をとって誤答する。
numeral = 40
when "卅", "丗"
numeral = 30
when "廿" ,"念", "\u5344", "\u5EFE"
numeral = 20
when "十", "拾"
numeral = 10
when "9", "九", "玖" #以下9数詞は命数素材にも確定記数にもなる。
numeral = 9
when "8", "八", "捌"
numeral = 8
when "7", "七", "漆", "質", "\u67D2"
numeral = 7
when "6", "六", "陸", "\u9646"
numeral = 6
when "5", "五", "伍"
numeral = 5
when "4", "四", "肆", "\u4989"
numeral = 4
when "3", "三", "参", "參", "\u5F0E", "\u53C1","\u53C4"
numeral = 3
when "2", "二", "弐", "弍", "貳", "貮", "\u8D30"
numeral = 2
when "1", "一", "壱", "弌", "壹"
numeral = 1
when "0", "〇", "零" #「〇」は十進記数法による桁上がり。
numeral = 0
else
return nil #変換対象とならない文字を読み込んだら nil を返す。
end
if numeral >= 10000 #確定中数を更新する数詞(万億兆)を読み込んだとき。
if lower_position > 0 #未確定の中数素材(10~9990)があるとき。
upper_position += (lower_position + decimal_number) * numeral
else #記数による未確定素材(1~9999)があるとき。
upper_position += [decimal_number, 1].max * numeral
end
lower_position = 0 #中数が確定したので素材をリセット。
decimal_number = 0 #命数が確定したので素材をリセット。
else
if numeral >= 10 #中数素材を更新する数詞(十廿~百千)を読み込んだとき。
lower_position += [decimal_number, 1].max * numeral #衝突しても計算続行。
decimal_number = 0 #命数が確定したので素材をリセット。
else #9数詞等(一~九、〇)を読み込んだとき。
decimal_number = decimal_number * 10 + numeral #十進法で記数を更新。
end
end
}
return upper_position + lower_position + decimal_number
end
end
end
using StringEx
#--- 定型句 -----------------------------------------------------------
PROMPT = "ユーザーIDとパスワードを入力してください"
LOGIN_ERR = "ユーザーIDまたはパスワードが正しくありません"
VALUE_LOGIN = "ログイン"
VALUE_LOGOUT = "ログアウト"
VALUE_RELOAD = "リロード"
UTF8_XMARK = "\u2715"
ORDER_DELETE = "削除"
NAME_UPLOAD_FILE = "upload_file"
NAME_COMMENT = "comment"
VALUE_COMMENT = "コメント"
VALUE_TRANSMIT = "送信"
VALUE_BACK = "戻る"
ORDER_DOWNLOAD = "ダウンロード"
ORDER_ERROR = "エラー"
VALUE_SORT = "ソート"
VALUE_ASC = "ascending"
VALUE_DESC = "descending"
VALUE_UNSET = "unset"
NAME_SORT = "sort_order"
V_CHAR = 1 # Numeral Sort by Character
# 0001<001<01<010<1<121万<1230000<2<3<i<ix<V<百二十二万
V_NUM = 2 # Numeral Sort by Numerical
# 1<01<001<0001<2<3<010<121万<1230000<i<ix<V<百二十二万
V_FIXED = 4 # Find Fixed Arabic Numerals
V_ROMAN = 8 # Find Roman Numerals
V_CHINESE = 16 # Find Chinese Numerals
# 01<001<010<0001<i<V<ix<1<2<3<121万<百二十二万<1230000
V_BIN = 32 # KANA Order by Binary
# 仮名照合をせず、バイナリ順でソートする。
V_JISX = 64 # KANA Order by JIS X 4061 Collation
# 長音<小書<繰返<清音で同順のときカタカナを後にする。
V_WIN = 128 # KANA Order by Windows Like Collation
# 小書<清音<繰返<長音で同順のときカタカナを先にする。
V_SJIS = 256 # Use UTF-8 Code in Collation
# 部首画数順。一<七<三<九<二<五<八<六<十<四
V_UTF8 = 512 # Use Shift_JIS Code in Collation
# 第1水準が五十音順。一<九<五<三<四<七<十<二<八<六
#--- CGI定型句 --------------------------------------------------------
HTTP_ERROR = "Status: 403 Forbidden\nContent-type: text/html\n\n"
RESPONSE_HEADER = "Content-type: text/html; charset=UTF-8\n\n"
#--- 前処理 -----------------------------------------------------------
c = CGI.new
user = Resolv.getname(c.remote_addr)
referer = ENV['HTTP_REFERER'].to_s
path_info = ENV['PATH_INFO'].to_s
order = c['ACTION'].to_s
login_id = c['LOGIN_ID'].to_s
login_pwd = c['LOGIN_PWD'].to_s
deregister = c['DELETE'].to_s
sort_order = c['NAME_SORT'].to_s
choose = path_info.gsub(/^\//,"")
files_list = File.read(LIST_FILE).split(/\/\"\R*/)
current_time = Time.now.strftime("(%Y/%m/%d %H:%M:%S)")
file_path_name = ""
local_name = ""
prompt = ""
opt_before = c['OPT_BEFORE'].to_i
if opt_before.zero?
numeral_sort = V_NUM
fixed_arabic = V_FIXED
numerical_roman = V_ROMAN
numerical_chinese = V_CHINESE
collation_order = V_JISX
collation_code = V_SJIS
opt_before = V_NUM + V_FIXED + V_ROMAN + V_CHINESE + V_JISX + V_SJIS
else
numeral_sort = c.params['NUMERAL_SORT'][0].to_i
fixed_arabic = c['FIXED_ARABIC'].to_i
numerical_roman = c['NUMERICAL_ROMAN'].to_i
numerical_chinese = c['NUMERICAL_CHINESE'].to_i
collation_order = c.params['COLLATION_ORDER'][0].to_i
collation_code = c.params['COLLATION_CODE'][0].to_i
end
opt_after = numeral_sort +
fixed_arabic +
numerical_roman +
numerical_chinese +
collation_order +
collation_code
ck_char = numeral_sort == V_CHAR ? "checked" : ""
ck_num = numeral_sort == V_NUM ? "checked" : ""
ck_fixed = fixed_arabic == V_FIXED ? "checked" : ""
ck_roman = numerical_roman == V_ROMAN ? "checked" : ""
ck_chinese = numerical_chinese == V_CHINESE ? "checked" : ""
ck_bin = collation_order == V_BIN ? "checked" : ""
ck_jisx = collation_order == V_JISX ? "checked" : ""
ck_win = collation_order == V_WIN ? "checked" : ""
ck_sjis = collation_code == V_SJIS ? "checked" : ""
ck_utf8 = collation_code == V_UTF8 ? "checked" : ""
#--- アクセスチェック -------------------------------------------------
case referer
when HOME_PAGE + UPLOAD_CGI
order = ORDER_ERROR if order != VALUE_BACK
order = ORDER_ERROR if path_info != ""
order = ORDER_ERROR if deregister != ""
when HOME_PAGE
case order
when VALUE_LOGIN, VALUE_LOGOUT, VALUE_RELOAD, VALUE_SORT
order = ORDER_ERROR if path_info != ""
order = ORDER_ERROR if deregister != ""
when ""
if path_info.empty?
if deregister.empty?
order = ORDER_ERROR
else
order = ORDER_DELETE
end
elsif deregister.empty?
order = ORDER_DOWNLOAD
else
order = ORDER_ERROR
end
else
order = ORDER_ERROR
end
else
order = ORDER_ERROR if order != ""
order = ORDER_ERROR if path_info != ""
order = ORDER_ERROR if deregister != ""
end
#--- ダウンロードファイル名の設定 --------------------------------------
if order == ORDER_DOWNLOAD
i=0
files_list.each_slice(6){|a|
if choose == a[0]
file_path_name = FILES_DIR + path_info + File.extname(a[2])
local_name = a[2]
break
end
i += 6
}
order = ORDER_ERROR if i >= files_list.length
end
#--- ファイル削除 ------------------------------------------------------
if order == ORDER_DELETE
i=0
files_list.each_slice(6){|a|
break if deregister == a[0]
i += 6
}
if i < files_list.length
files_list.slice!(i,6)
File.open(LIST_FILE, "w"){ |fh|
fh.flock(File::LOCK_EX)
files_list.each_slice(6){|a|
fh.print a[0] + "/\""
fh.print a[1] + "/\""
fh.print a[2] + "/\""
fh.print a[3] + "/\""
fh.print a[4] + "/\""
fh.print a[5] + "/\"\n"
}
fh.flock(File::LOCK_UN)
}
else
order = ORDER_ERROR
end
end
#--- ファイルリストのソート --------------------------------------------
case order
when VALUE_SORT, ORDER_DELETE
if order == VALUE_SORT
if sort_order == VALUE_ASC
sort_order = VALUE_DESC if opt_before == opt_after
else
sort_order = VALUE_ASC
end
end
if sort_order != VALUE_UNSET
#---- 照合用配列の作成 ---------------------------------------------
work = Array.new
files_list.each_slice(6){|a|
#---- かな照合用キーの作成 ---------------------------------------
if collation_order == V_BIN
k4 = ""
k3 = a[2]
k2 = NKF.nkf('-WwxZ1m0',a[2])
k1 = k2.upcase
else
#---- ひらがな、カタカナ、カタカナ、abc、ABC --------------------
k4 = a[2]
#---- アー、アァ、アヽ、アア、abc、ABC -------------------------
k3 = NKF.nkf('-WwZ1h2m0', k4)
k3.gsub!(/([パピプペポ])/,'\1゜')
k3.tr!("パピプペポ","ハヒフヘホ")
k3.gsub!(/([ガギグゲゴザジズゼゾダヂヅデドバビブベボヴヾ])/,'\1゛')
k3.tr!("ガギグゲゴザジズゼゾダヂヅデドバビブベボヴヾ","カキクケコサシスセソタチツテトハヒフヘホウヽ")
k3.gsub!(/([\u30F7\u30F8\u30F9\u30FA])/,'\1゛') #ワ゛ヰ゛ヱ゛ヲ゛
k3.tr!("\u30F7\u30F8\u30F9\u30FA","ワヰヱヲ")
k3.tr!("\u3099\u309A","\u309B\u309C") # COMBINING KATAKANA-HIRAGANA (SEMI-)VOICED SOUND MARK
k2 = k3.upcase # かな類の小書きを清音へASCII小文字を大文字へ
case collation_order
when V_WIN
k3.gsub!(/([ヵヶ])/,"\e\\1")
k3.gsub!(/([\u31F0-\u31FF])/,"\e\\1")
k3.gsub!(/(ー)/,"\uFFFD\\1")
when V_JISX
k3.gsub!(/(ー)/,"\e\e\e\\1")
k3.gsub!(/([ァィゥェォッャュョヮヵヶ])/,"\e\e\\1")
k3.gsub!(/([\u31F0-\u31FF])/,"\e\e\\1")
k3.gsub!(/(ヽ)/,"\e\\1")
end
#---- ふ、ふ゛、ふ゜、ABC、ABC ---------------------------------
k2.tr!("ァィゥェォッャュョヮヵヶ","アイウエオツヤユヨワカケ")
k2.tr!("\u31F0-\u31FF","クシストヌハヒフヘホムラ-ロ")
k2.gsub!(/([アカサタナハマヤラワ][゛゜ヽ]*)ー/,'\1ア')
k2.gsub!(/([イキシチニヒミリヰ][゛゜ヽ]*)ー/,'\1イ')
k2.gsub!(/([ウクスツヌフムユル][゛゜ヽ]*)ー/,'\1ウ')
k2.gsub!(/([エケセテネヘメレヱ][゛゜ヽ]*)ー/,'\1エ')
k2.gsub!(/([オコソトノホモヨロヲ][゛゜ヽ]*)ー/,'\1オ')
k2.gsub!(/([ン][゛゜ヽ]*)ー/,'\1ン')
k2.gsub!(/([ア-ン])([゛゜]*)ヽ/,'\1\2\1')
k2.gsub!(/(゛|゜)/,"\uFFFD\\1")
#---- ふ、ふ、ふ、ABC、ABC -------------------------------------
k1 = k2.delete("\uFFFD゛|\uFFFD゜")
end
#---- 数値照合用キーの作成 ---------------------------------------
if numeral_sort == V_NUM
#--- 丸付き数字は数値化せずに CIRCLED DIGIT へ統合する ---------
k1.tr!("\u2474-\u2487","\u2460-\u2473") # PARENTHESIZED DIGIT
k1.tr!("\u2488-\u249B","\u2460-\u2473") # DIGIT FULL STOP
k1.tr!("\u24EB-\u24F4","\u246A-\u2473") # NEGATIVE CIRCLED NUMBER
k1.tr!("\u24F5-\u24FE","\u2460-\u2469") # DOUBLE CIRCLED DIGIT
k1.tr!("\u2776-\u277F","\u2460-\u2469") # DINGBAT NEGATIVE CIRCLED DIGIT
k1.tr!("\u2780-\u2789","\u2460-\u2469") # DINGBAT CIRCLED SANS-SERIF DIGIT
k1.tr!("\u278A-\u2793","\u2460-\u2469") # DINGBAT NEGATIVE CIRCLED SANS-SERIF DIGIT
k1.gsub!(/\u24EA/,"\u2460\e") # CIRCLED DIGIT ZERO は CIRCLED DIGIT ONE の前へ
k1.gsub!(/\u24FF/,"\u2460\e") # NEGATIVE CIRCLED DIGIT ZERO は CIRCLED DIGIT ONE の前へ
#--- アラビア数字の数値化 --------------------------------------
k1.gsub!(/([1-9][\d]*)|(0[\d]*)/) {
if $1.to_i > 0
"%016d" % $1.to_i # [,.]は数値を分割する
elsif fixed_arabic == V_FIXED
"\e\e%d" % $2.to_s.length + $2 # 固定長は分類しソート後、先頭へ
else
"%016d" % $2.to_i # 固定長でも混在させてソート
end
}
#--- 漢数字の数値化 --------------------------------------------
k1.gsub!(/(#{REG_NUMERICAL})/){ "%016d" % $1.value } if numerical_chinese == V_CHINESE
#--- ローマ数字の数値化 ----------------------------------------
if numerical_roman == V_ROMAN
k1.tr!("\u2170-\u217F","\u2160-\u216F") # SMALL ROMAN NUMERAL を統合
k1.gsub!(/((?:\b[IVXLCDM]+)?[\u2160-\u216F]+[IVXLCDM\u2160-\u216F]*)/,"\e\\1\e") # ASCIIとの混在を検出
k1.gsub!(/[\u2160-\u216F]/,ROMAN_ASCII_TABLE) # ASCIIへ統合
k1.gsub!(/(\e?\b(M{0,3})(CM|CD|D?C{0,3})(XC|XL|L?X{0,3})(IX|IV|V?I{0,3})\b\e?)/){
m = $1.delete("\e")
if m.empty?
$1
else
m.gsub!(/(C(?=[DM])|X(?=[CL])|I(?=[XV]))/,'-(\&)')
m.gsub!(/[IVXLCDM]/,ROMAN_ARABIC_TABLE)
"\e%016d" % eval(m)
end
}
end
end
work << [k1, k2, k3, k4, a[0], a[1], a[2], a[3], a[4], a[5]]
}
#---- 照合用配列のソート -------------------------------------------------------
option_string = collation_code == V_SJIS ? '-Wsxm0' : '-Wwxm0'
case sort_order
when VALUE_ASC
work.sort!{ |a, b|
(NKF.nkf(option_string,a[0]) <=> NKF.nkf(option_string,b[0])).nonzero? ||
(a[1]<=>b[1]).nonzero? ||
(a[2]<=>b[2]).nonzero? ||
(collation_order == V_WIN ? b[3]<=>a[3] : a[3]<=>b[3])
}
else
work.sort!{ |b, a|
(NKF.nkf(option_string,a[0]) <=> NKF.nkf(option_string,b[0])).nonzero? ||
(a[1]<=>b[1]).nonzero? ||
(a[2]<=>b[2]).nonzero? ||
(collation_order == V_WIN ? b[3]<=>a[3] : a[3]<=>b[3])
}
end
#---- ソート結果をファイルリストへ反映 --------------------------------
work.flatten!
files_list = Array.new
work.each_slice(10){|a| files_list.push(a[4],a[5],a[6],a[7],a[8],a[9])}
end
else
sort_order = VALUE_UNSET
end
#--- リストを一覧表にする --------------------------------------------------------------------------
table_data = "<table border=\"1\" cellpadding=\"5\"><caption>ファイル一覧 #{ current_time }</caption>"
table_data << "<tr><th>投稿日</th><th>ファイル名 [サイズ]</th>"
table_data << "<th>コメント</th><th>ホスト名</th><th>削除</th></tr>"
files_list.each_slice(6){|a|
table_data << "<tr><td>#{ a[1] }</td><td>"
table_data << "<a href=\"#{ INDEX_CGI }/#{ a[0] }\" target=\"_blank\">#{ a[2] }"
table_data << "</a> #{ a[3] }</td><td>#{ a[4] }</td><td>#{ a[5] }</td><th>"
if a[5] == user
table_data << "<button type=\"submit\" name=\"DELETE\" value=\"#{ a[0] }\">#{ UTF8_XMARK }</button>"
end
table_data << "</th></tr>"
}
table_data << "</table>"
#--- アップロードフォームひな形 --------------------------------------------------------
upload_form = <<"EOS"
<form action="#{ UPLOAD_CGI }" method="post" enctype="multipart/form-data">
<table cellpadding="5"><tr><td><input type="FILE" name="upload_file" required>
</td></tr><tr><td><input type="text" name="comment" value="#{ VALUE_COMMENT }" size="100">
<input type="submit" value="#{ VALUE_TRANSMIT }"></td></tr></table></form>
<hr>
<form action="." method="post"><br>
<input type="submit" name="ACTION" value="#{ VALUE_RELOAD }">
<input type="submit" name="ACTION" value="#{ VALUE_SORT }">
<input type="submit" name="ACTION" value="#{ VALUE_LOGOUT }">
<input type="hidden" name="NAME_SORT" value="#{ sort_order }">
<input type="hidden" name="OPT_BEFORE" value="#{ opt_after }">
<table><tr><td>数字順
<input type="radio" name="NUMERAL_SORT" value="#{ V_CHAR }" #{ ck_char }>CHAR
<input type="radio" name="NUMERAL_SORT" value="#{ V_NUM }" #{ ck_num }>NUM(
<input type="checkbox" name="FIXED_ARABIC" value="#{ V_FIXED }" #{ ck_fixed }>03<002<1
<input type="checkbox" name="NUMERICAL_ROMAN" value="#{ V_ROMAN }" #{ ck_roman }>IV=4
<input type="checkbox" name="NUMERICAL_CHINESE" value="#{ V_CHINESE }" #{ ck_chinese }>五=5 )
</td></tr><tr><td>かな順
<input type="radio" name="COLLATION_ORDER" value="#{ V_BIN }" #{ ck_bin }>BIN
<input type="radio" name="COLLATION_ORDER" value="#{ V_JISX }" #{ ck_jisx }>JISX
<input type="radio" name="COLLATION_ORDER" value="#{ V_WIN }" #{ ck_win }>WIN / 漢字順
<input type="radio" name="COLLATION_CODE" value="#{ V_SJIS }" #{ ck_sjis }>SJIS
<input type="radio" name="COLLATION_CODE" value="#{ V_UTF8 }" #{ ck_utf8 }>UTF8
</td></tr></table>
#{ table_data }
<br><br><br></form>
EOS
#--- ログインフォームひな形 -----------------------------------------------------------
login_form = <<"EOS"
<form action="." method="post"><table cellpadding="5">
<tr><td>ユーザーID</td><td><input type="text" name="LOGIN_ID" size="20"></td></tr>
<tr><td>パスワード</td><td><input type="password" name="LOGIN_PWD" size="20"></td></tr>
</table><br><input type="submit" name="ACTION" value="#{ VALUE_LOGIN }"></form>
EOS
#--- HTMLひな形 --------------------------------------------------------------------------------
html_beginning = <<"EOS"
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>#{ SITE_TITLE }</title>
<base href="#{ HOME_PAGE }">
<link rel="canonical" href="#{ HOME_PAGE }">
</head>
<body bgcolor="#{ BODY_BGCOLOR }" text="#{ BODY_TEXT_COLOR }">
<div align="center">
<h1><font color="#{ TITLE_FONT_COLOR }">#{ PAGE_TITLE }</font></h1>
<hr>
EOS
html_ending = "</div>\n</body>\n</html>"
#--- HTML出力 ---------------------------------------------------------------
case order
when VALUE_LOGIN
prompt = ""
if (login_id + login_pwd).empty?
prompt = PROMPT
elsif login_id != USER_ID
prompt = LOGIN_ERR
elsif login_pwd != USER_PWD
prompt = LOGIN_ERR
end
print RESPONSE_HEADER
print html_beginning
if prompt == ""
print upload_form
else
print prompt
print login_form
end
print html_ending
when VALUE_LOGOUT, ""
print RESPONSE_HEADER
print html_beginning
print PROMPT
print login_form
print html_ending
when VALUE_RELOAD, VALUE_BACK, VALUE_SORT, ORDER_DELETE
print RESPONSE_HEADER
print html_beginning
print upload_form
print html_ending
when ORDER_DOWNLOAD
enc_name = CGI.escape(local_name).gsub(/\+/,"%20")
open(file_path_name) {|fp|
param = {
'Content-Type' => "application/octet-stream",
'Content-Length' => fp.stat.size,
'Expires' => 0,
'Cache-Control' => "must-revalidate, post-check=0,pre-check=0",
'Pragma' => "private",
'Content-Disposition' => "attachment;filename=\"#{ local_name }\";filename*=utf-8''#{ enc_name }"
}
c.out(param){
fp.read
}
}
else
print HTTP_ERROR
end