1 #!/usr/local/bin/ruby
\r
2 # -*- coding: utf-8 -*-
\r
4 #= Galleryマネージャ用アプリケーション
\r
6 #Autohr:: Kureha Hisame (http://lunardial.sakura.ne.jp/)
\r
8 #Copyright:: Copyright 2013 Kureha Hisame (http://lunardial.sakura.ne.jp/)
\r
12 require "cgi/session"
\r
14 require "rexml/document"
\r
18 require "./common.rb"
\r
19 require "./define.rb"
\r
21 # = WebSecurityExceptionクラス
\r
23 # 独自定義の例外クラスです。WebFilerインスタンス内の処理でセキュリティ違反が発生した場合にthrowされます。
\r
24 class WebSecurityException < Exception
\r
27 # = FileExistedExceptionクラス
\r
29 # 独自定義の例外クラスです。WebFileインスタンスの処理で、既に存在するファイルに上書きしようとした場合にthrowされます。
\r
30 class FileExistedException < Exception
\r
33 # = FileNotExistedExceptionクラス
\r
35 # 独自定義の例外クラスです。WebFileインスタンスの処理で、対象ファイルが存在しない場合にthrowされます。
\r
36 class FileNotExistedException < Exception
\r
41 # テンプレートファイル(*.erb)を読み込み、管理するクラスです
\r
45 # _template_ :: テンプレートファイル(*.erb)のパス
\r
46 # _binding_ :: binding変数
\r
47 def initialize(template, binding)
\r
48 @erb = ERB.new(myopen(template, "r:utf-8") {|f| f.read}, nil, "-")
\r
52 # テンプレートファイルの文字列を返却するメソッドです
\r
54 @erb.result(@binding)
\r
60 # Web上にローカルと同じフォルダ管理機能を利用できるクラスです
\r
64 # _basepath_ :: クラス内で扱う最上位のフォルダ(root)とする実パス
\r
65 def initialize(basepath)
\r
66 @basepath = basepath
\r
67 @basepath << "/" unless @basepath[-1..-1] == "/"
\r
72 raise "Target dir not found." unless File.directory?(pwd)
\r
75 # ファイルに使用できない文字列を調べるための正規表現を定義します
\r
76 FILEREGEXP = /\A[-_+~^0-9a-zA-Z]+(\.[-_+~^0-9a-zA-Z]+)*\z/
\r
78 attr_reader :basepath
\r
79 attr_accessor :relpath_list, :sort_type, :sort_reverse
\r
81 # ディレクトリ内部のファイル・フォルダ一覧を取得するメソッド
\r
83 filelist = Dir::entries(pwd)
\r
84 filelist.delete(".")
\r
85 filelist.delete("..")
\r
90 if @sort_reverse == "true"
\r
91 filelist.sort!{|a, b|
\r
92 (File.ftype(pwd + b) <=> File.ftype(pwd + a)).nonzero? ||
\r
93 (File.basename(pwd + a) <=> File.basename(pwd + b))
\r
96 filelist.sort!{|a, b|
\r
97 (File.ftype(pwd + a) <=> File.ftype(pwd + b)).nonzero? ||
\r
98 (File.basename(pwd + a) <=> File.basename(pwd + b))
\r
102 filelist.sort!{|a, b| File.ctime(pwd + b) <=> File.ctime(pwd + a) }
\r
104 filelist.reverse! if @sort_reverse == "true"
\r
106 filelist.sort!{|a, b| File.mtime(pwd + b) <=> File.mtime(pwd + a) }
\r
108 filelist.reverse! if @sort_reverse == "true"
\r
110 if @sort_reverse == "true"
\r
111 filelist.sort!{|a, b|
\r
112 (File.ftype(pwd + a) <=> File.ftype(pwd + b)).nonzero? ||
\r
113 (File.size(pwd + a) <=> File.size(pwd + b)).nonzero? ||
\r
114 (File.basename(pwd + a) <=> File.basename(pwd + b))
\r
117 filelist.sort!{|a, b|
\r
118 (File.ftype(pwd + a) <=> File.ftype(pwd + b)).nonzero? ||
\r
119 (File.size(pwd + b) <=> File.size(pwd + a)).nonzero? ||
\r
120 (File.basename(pwd + a) <=> File.basename(pwd + b))
\r
124 filelist.sort!{|a, b| File.basename(pwd + a) <=> File.basename(pwd + b) }
\r
126 filelist.reverse! if @sort_reverse == "true"
\r
128 if @sort_reverse == "true"
\r
129 filelist.sort!{|a, b|
\r
130 (File.ftype(pwd + b) <=> File.ftype(pwd + a)).nonzero? ||
\r
131 (File.basename(pwd + a) <=> File.basename(pwd + b))
\r
134 filelist.sort!{|a, b|
\r
135 (File.ftype(pwd + a) <=> File.ftype(pwd + b)).nonzero? ||
\r
136 (File.basename(pwd + a) <=> File.basename(pwd + b))
\r
144 # ディレクトリ内部のファイル・フォルダ一覧の詳細情報を取得するメソッド
\r
146 filelist = Dir::entries(pwd)
\r
147 filelist.delete(".")
\r
148 filelist.delete("..")
\r
151 filelist.each { |fname|
\r
152 fileinfo[fname] = {}
\r
153 fileinfo[fname][:ftype] = File.ftype(pwd + "/" + fname)
\r
154 fileinfo[fname][:atime] = File.atime(pwd + "/" + fname)
\r
155 fileinfo[fname][:ctime] = File.ctime(pwd + "/" + fname)
\r
156 fileinfo[fname][:mtime] = File.mtime(pwd + "/" + fname)
\r
157 fileinfo[fname][:size] = File.size(pwd + "/" + fname) / 1000
\r
159 fileinfo[fname][:sort] = File.mtime(pwd + "/" + fname).to_i
\r
167 File.ftype(pwd + File.basename(fname))
\r
172 if pathname == ".."
\r
173 @relpath_list.delete_at(-1) unless @relpath_list.length == 0
\r
174 elsif pathname.match(FILEREGEXP)
\r
175 if File.directory?(pwd + "/" + File.basename(pathname))
\r
176 @relpath_list << File.basename(pathname)
\r
178 raise FileExistedException
\r
181 raise WebSecurityException
\r
185 # ディレクトリを絶対指定で移動するメソッド
\r
186 def cd_abs(relpath_arr)
\r
187 relpath_arr.each { |name|
\r
188 unless name.match(FILEREGEXP)
\r
189 raise WebSecurityException
\r
192 @relpath_list = relpath_arr
\r
195 # 現在のディレクトリを表示するメソッド
\r
197 @basepath + relpath
\r
202 if @relpath_list.length == 0
\r
205 @relpath_list.join("/") << "/"
\r
209 # ファイルをアップロードするメソッド
\r
210 def upload(file, fname)
\r
211 fname.gsub!(/( | )/, "_")
\r
213 if File.exist?(pwd + File.basename(fname))
\r
214 raise FileExistedException
\r
215 elsif File.basename(fname).match(FILEREGEXP)
\r
216 open(pwd + File.basename(fname), "w") do |f|
\r
221 raise WebSecurityException
\r
226 def move(from_name, dest_name)
\r
227 if File.exist?(pwd + File.basename(dest_name))
\r
228 raise FileExistedException
\r
231 unless File.exist?(pwd + File.basename(from_name))
\r
232 raise FileNotExistedException
\r
235 unless File.basename(from_name).match(FILEREGEXP)
\r
236 raise WebSecurityException
\r
239 unless File.basename(dest_name).match(FILEREGEXP)
\r
240 raise WebSecurityException
\r
243 File.rename(pwd + File.basename(from_name), pwd + File.basename(dest_name))
\r
248 if File.exist?(pwd + File.basename(fname)) && fname.match(FILEREGEXP)
\r
249 File.delete(pwd + File.basename(fname))
\r
251 raise WebSecurityException
\r
257 dirname.gsub!(/( | )/, "_")
\r
258 if File.exist?(pwd + File.basename(dirname))
\r
259 raise FileExistedException
\r
260 elsif dirname.match(FILEREGEXP)
\r
261 Dir.mkdir(pwd + File.basename(dirname))
\r
263 raise WebSecurityException
\r
267 # 内部が空のディレクトリを消去するメソッド
\r
269 if File.exist?(pwd + File.basename(dirname)) && dirname.match(FILEREGEXP)
\r
270 Dir.rmdir(pwd + File.basename(dirname))
\r
272 raise WebSecurityException
\r
280 # コントローラ部分に相当する処理を受け持つクラスです
\r
282 def self.update_session(session, filer)
\r
283 session["filelist"] = filer.ls
\r
284 session["fileinfo"] = filer.lsinfo
\r
285 session["sort_type"] = filer.sort_type
\r
286 session["sort_reverse"] = filer.sort_reverse
\r
287 session["pwd"] = filer.pwd
\r
288 session["relpath_list"] = filer.relpath_list.join("/")
\r
291 def Controller.MultiForm(cgi, session, params, db)
\r
294 filer = WebFiler.new(IMGPATH)
\r
296 filer.relpath_list = params["relpath_list"].split("/")
\r
297 filer.sort_type = params["sort_type"]
\r
298 filer.sort_reverse = params["sort_reverse"]
\r
301 filer.sort_type = "ftype" if filer.sort_type == nil or filer.sort_type.empty?
\r
302 Controller.update_session(session, filer);
\r
304 case params["action"]
\r
307 if (cgi["updata"].size == 0)
\r
308 session["error"] = "アップロードするファイルが選択されていません!"
\r
309 elsif (cgi["updata"].size <= UPLOADLIMIT)
\r
312 upload_filename = nil
\r
313 unless params["file_rename"].empty?
\r
314 upload_filename = File.basename(params["file_rename"])
\r
316 upload_filename.gsub!(/( | )/, "_")
\r
318 upload_filename = cgi["updata"].original_filename
\r
321 filer.upload(cgi["updata"], upload_filename)
\r
323 if params["thumbs"] == "true" and File.extname(upload_filename) =~ /\.(jpg|JPG|png|PNG)\Z/
\r
325 require('./resize.rb')
\r
326 if filer.relpath_list.size == 0
\r
327 ResizeManager.create_thumbs(IMGPATH + upload_filename)
\r
329 ResizeManager.create_thumbs(IMGPATH + filer.relpath_list.join("/") + "/" + upload_filename)
\r
335 session["error"] = "サムネイル作成に失敗しました。<br>"
\r
336 session["error"] << evar.to_s
\r
340 rescue FileExistedException
\r
341 session["error"] = "既に同名のファイルが存在します!"
\r
342 rescue WebSecurityException
\r
343 session["error"] = "ファイル名に使用できない文字列が含まれています!"
\r
346 session["error"] = "ファイルの容量が大きすぎます!"
\r
350 Controller.update_session(session, filer);
\r
352 session["info"] = "正常にファイル(#{upload_filename})のアップロードが完了しました。" if session["error"] == ""
\r
356 session["selectlist"] = []
\r
359 dest_name = params["destname"]
\r
360 session["filelist"].each do |file|
\r
361 if params["filename_" + file] == "true"
\r
368 mes = "対象が選択されていません。"
\r
369 session["error"] = mes
\r
371 mes = "一つ以上の対象がチェックされています。<br>"
\r
372 mes << "リネーム処理は一度に一つの対象にしか行えません。"
\r
373 session["error"] = mes
\r
374 elsif dest_name.empty?
\r
375 mes = "リネーム名称が入力されていません。"
\r
376 session["error"] = mes
\r
379 filer.move(from_name, dest_name)
\r
380 rescue FileExistedException
\r
381 session["error"] = "既に同名のファイルが存在します!"
\r
382 rescue FileNotExistedException
\r
383 session["error"] = "選択したファイルは既に削除されました。"
\r
384 rescue WebSecurityException
\r
385 session["error"] = "リネーム名称に使用できない文字列が含まれています!"
\r
390 Controller.update_session(session, filer);
\r
392 session["info"] = "正常にファイルのリネームが完了しました。" if session["error"] == ""
\r
396 session["dellist"] = []
\r
398 session["filelist"].each do |file|
\r
399 if params["filename_" + file] == "true" && filer.ftype(file) == "file"
\r
400 filer.delete(file)
\r
402 elsif params["filename_" + file] == "true" && filer.ftype(file) == "directory"
\r
407 mes = "対象のフォルダは空ではありません!<br>"
\r
408 mes << "フォルダを削除する場合は、事前にフォルダ内部の全てのファイルを削除してください。"
\r
409 session["error"] = mes
\r
415 Controller.update_session(session, filer);
\r
417 session["info"] = "正常にファイルの削除が完了しました。" if session["error"] == "" && count != 0
\r
422 filer.mkdir(params["dirname"])
\r
423 rescue FileExistedException
\r
424 session["error"] = "既に同名のフォルダが存在します!"
\r
425 rescue WebSecurityException
\r
426 session["error"] = "フォルダ名に使用できない文字列が含まれています!"
\r
430 Controller.update_session(session, filer);
\r
432 session["info"] = "正常にフォルダの作成が完了しました。" if session["error"] == ""
\r
437 filer.cd(params["arg"])
\r
439 session["error"] = "移動先のフォルダが見つかりません!"
\r
443 Controller.update_session(session, filer);
\r
447 if params["arg"].to_i >= 0
\r
450 params["arg"].to_i.times { |i|
\r
451 movepath << params["relpath_list"].split("/")[i]
\r
453 filer.cd_abs(movepath)
\r
455 session["error"] = "移動先のフォルダが見つかりません!"
\r
458 session["error"] = "移動先のフォルダが見つかりません!"
\r
462 Controller.update_session(session, filer);
\r
476 # SESSION変数、パラメータなどを取得します
\r
478 session = CGI::Session.new(cgi)
\r
479 params = Hash[*cgi.params.to_a.map{|k, v| [k, v[0].to_s]}.flatten]
\r
480 params.each { |k, v| params[k] = cgi[k].read if cgi[k].respond_to?(:read) && k != "updata"}
\r
483 logger = WebLogger.get_logger(cgi.script_name, LOG_DIR, LOG_RELEASE_MODE)
\r
487 session["info"] = ""
\r
488 session["error"] = ""
\r
489 if session["login"] != "true"
\r
491 LOGININFO.each {|h|
\r
492 if (cgi["loginid"] == h[:id] && cgi["password"] == h[:password])
\r
493 session["login"] = "true"
\r
494 session["name"] = h[:name]
\r
497 logger.info "ログインユーザ:#{h[:id]}, IPアドレス:#{cgi.remote_addr}"
\r
499 # ワークフォルダの中をクリーンアップします
\r
500 filelist = Dir::entries("./work")
\r
501 # 削除条件 : 最終変更日時から1日(60*60*24sec)かつ、ファイルタイプがファイルの場合
\r
502 filelist.each do |file|
\r
503 File.delete("./work/#{file}") if Time.now - File.ctime("./work/#{file}") > 86400 && File.ftype("./work/#{file}") == "file"
\r
510 if (session["login"] != "true" and (cgi["loginid"] != "" or cgi["password"] != ""))
\r
511 session["error"] = "ログインに失敗しました。ユーザIDまたはパスワードを確認して下さい。"
\r
512 logger.info "次のアクセスがログインに失敗しました。ログインID:#{cgi["loginid"]}, IPアドレス:#{cgi.remote_addr}"
\r
517 if params["mode"] == "logout"
\r
518 session["login"] = nil
\r
519 session["logini"] = nil
\r
520 session["password"] = nil
\r
526 # セッションが有効な場合のみコントローラを実行します
\r
527 if session["login"] == "true"
\r
528 db = PStore.new("./work/#{session.session_id}_file.dat")
\r
530 Controller.MultiForm(cgi, session, params, db)
\r
534 if session["login"] != "true"
\r
535 # セッションが存在しない場合は強制的にエラーページに遷移
\r
536 htmlwriter = HtmlWriter.new("./erbtemp/login.html.erb", binding)
\r
538 htmlwriter = HtmlWriter.new("./erbtemp/filemanager.html.erb", binding)
\r
542 cgi.out{htmlwriter.to_code}
\r
543 rescue => exception
\r
545 logger.error(exception.to_s)
\r
546 logger.error(exception.backtrace.join "\n")
\r
548 # エラーが発生した場合、それを画面に表示します
\r
549 htmlwriter = HtmlWriter.new("./erbtemp/exception.html.erb", binding)
\r
550 cgi.out{ htmlwriter.to_code }
\r
557 # エラーが発生した場合、それを画面に表示します
\r
558 detail = ("%s: %s (%s)\n" %
\r
559 [evar.backtrace[0], evar.message, evar.send('class')]) +
\r
560 evar.backtrace[1..-1].join("\n")
\r
561 puts "content-type: text/html\n\n<plaintext>\n" + detail
\r