2 # -*- coding: utf-8 -*-
4 #= FeedGeneratorから起動するファイルマネージャWEBアプリケーション
6 #Autohr:: Kureha Hisame (http://lunardial.sakura.ne.jp/) & Yui Naruse (http://airemix.com/)
8 #Copyright:: Copyright 2009 FeedBlog Project (http://sourceforge.jp/projects/feedblog/)
14 require "rexml/document"
21 IMGPATH = "./../lunardial/xml/img/"
24 APPVERSION = "- FileManager for Ruby version 2.0.0.0 -<br>Copyright(c) 2009 Kureha.H (<a href=\"http://lunardial.sakura.ne.jp/\" target=\"_blank\">http://lunardial.sakura.ne.jp/</a>) & Yui Naruse (<a href=\"http://airemix.com/\" target=\"_blank\">http://airemix.com/</a>)"
26 APPTITLE = "FileManager for Ruby version 2.0.0.0"
29 UPLOADLIMIT = 2 * 1024 * 1024
37 # ruby-1.9.x以降ではファイルを開いた際、エンコードの指定を行わないとエラーの原因になります。
38 # ただしruby-1.8.6以前はエンコードの指定に対応していないため、独自メソッドを定義してファイルの入出力を行います。
40 # _arg[0]_ :: 入出力を行うファイルのパス
41 # _arg[1]_ :: モードの指定。例 : w:utf-8(書き込みモード・UTF-8エンコードでファイルを開く)
44 arg[1] = mode[/[^:]+/] if mode && RUBY_VERSION < "1.8.7" && mode.include?(':')
46 f.flock(/\A\w+r/ =~ mode ? File::LOCK_SH : File::LOCK_EX)
70 # = WebSecurityExceptionクラス
72 # 独自定義の例外クラスです。WebFilerインスタンス内の処理でセキュリティ違反が発生した場合にthrowされます。
73 class WebSecurityException < Exception
76 # = FileExistedExceptionクラス
78 # 独自定義の例外クラスです。WebFileインスタンスの処理で、既に存在するファイルに上書きしようとした場合にthrowされます。
79 class FileExistedException < Exception
84 # テンプレートファイル(*.erb)を読み込み、管理するクラスです
88 # _template_ :: テンプレートファイル(*.erb)のパス
89 # _binding_ :: binding変数
90 def initialize(template, binding)
91 @erb = ERB.new(myopen(template, "r:utf-8") {|f| f.read}, nil, "-")
95 # テンプレートファイルの文字列を返却するメソッドです
103 # Web上にローカルと同じフォルダ管理機能を利用できるクラスです
107 # _basepath_ :: クラス内で扱う最上位のフォルダ(root)とする実パス
108 def initialize(basepath)
110 @basepath << "/" unless @basepath[-1..-1] == "/"
113 raise "Target dir not found." unless File.directory?(pwd)
116 # ファイルに使用できない文字列を調べるための正規表現を定義します
117 FILEREGEXP = /\A[-_+~^0-9a-zA-Z]+(\.[-_+~^0-9a-zA-Z]+)*\z/
119 attr_reader :basepath
120 attr_accessor :relpath_list
122 # ディレクトリ内部のファイル・フォルダ一覧を取得するメソッド
124 filelist = Dir::entries(pwd)
126 filelist.delete("..")
131 # ディレクトリ内部のファイル・フォルダ一覧の詳細情報を取得するメソッド
133 filelist = Dir::entries(pwd)
135 filelist.delete("..")
138 filelist.each { |fname|
140 fileinfo[fname][:ftype] = File.ftype(pwd + "/" + fname)
141 fileinfo[fname][:atime] = File.atime(pwd + "/" + fname)
142 fileinfo[fname][:ctime] = File.ctime(pwd + "/" + fname)
143 fileinfo[fname][:mtime] = File.mtime(pwd + "/" + fname)
144 fileinfo[fname][:size] = File.size(pwd + "/" + fname) / 1000
152 File.ftype(pwd + File.basename(fname))
158 @relpath_list.delete_at(-1) unless @relpath_list.length == 0
159 elsif pathname.match(FILEREGEXP)
160 if File.directory?(pwd + "/" + File.basename(pathname))
161 @relpath_list << File.basename(pathname)
163 raise FileExistedException
166 raise WebSecurityException
170 # ディレクトリを絶対指定で移動するメソッド
171 def cd_abs(relpath_arr)
172 relpath_arr.each { |name|
173 unless name.match(FILEREGEXP)
174 raise WebSecurityException
177 @relpath_list = relpath_arr
187 if @relpath_list.length == 0
190 @relpath_list.join("/") << "/"
195 def upload(file, fname)
196 fname.gsub!(/( | )/, "_")
197 if File.exist?(pwd + File.basename(fname))
198 raise FileExistedException
199 elsif File.basename(fname).match(FILEREGEXP)
200 open(pwd + File.basename(fname), "w") do |f|
205 raise WebSecurityException
211 if File.exist?(pwd + File.basename(fname)) && fname.match(FILEREGEXP)
212 File.delete(pwd + File.basename(fname))
214 raise WebSecurityException
220 dirname.gsub!(/( | )/, "_")
221 if File.exist?(pwd + File.basename(dirname))
222 raise FileExistedException
223 elsif dirname.match(FILEREGEXP)
224 Dir.mkdir(pwd + File.basename(dirname))
226 raise WebSecurityException
230 # 内部が空のディレクトリを消去するメソッド
232 if File.exist?(pwd + File.basename(dirname)) && dirname.match(FILEREGEXP)
233 Dir.rmdir(pwd + File.basename(dirname))
235 raise WebSecurityException
243 # コントローラ部分に相当する処理を受け持つクラスです
245 def Controller.MultiForm(cgi, session, params, db)
247 case params["action"]
250 filer = WebFiler.new(IMGPATH)
251 filer.relpath_list = session["relpath_list"].split("/")
253 if (cgi["updata"].size <= UPLOADLIMIT)
255 filer.upload(cgi["updata"], cgi["updata"].original_filename)
256 rescue FileExistedException
257 db["error"] = "既に同名のファイルが存在します!"
258 rescue WebSecurityException
259 db["error"] = "ファイル名に使用できない文字列が含まれています!"
262 db["error"] = "ファイルの容量が大きすぎます!"
265 db["filelist"] = filer.ls.reverse
266 db["fileinfo"] = filer.lsinfo
267 session["relpath_list"] = filer.relpath_list.join("/")
269 db["info"] = "正常にアップロードが完了しました。" if db["error"] == ""
273 filer = WebFiler.new(IMGPATH)
274 filer.relpath_list = params["relpath_list"].split("/")
278 db["filelist"].each do |file|
279 if params["filename_" + file] == "delete" && filer.ftype(file) == "file"
282 elsif params["filename_" + file] == "delete" && filer.ftype(file) == "directory"
286 mes = "対象のディレクトリは空ではありません!<br>"
287 mes << "ディレクトリを削除する場合は、事前にディレクトリ内部の全てのファイルを削除してください。"
293 db["filelist"] = filer.ls.reverse
294 db["fileinfo"] = filer.lsinfo
295 session["relpath_list"] = filer.relpath_list.join("/")
297 db["info"] = "正常にファイルの削除が完了しました。" if db["error"] == "" && count != 0
301 filer = WebFiler.new(IMGPATH)
302 filer.relpath_list = params["relpath_list"].split("/")
305 filer.mkdir(params["dirname"])
306 rescue FileExistedException
307 db["error"] = "既に同名のディレクトリが存在します!"
308 rescue WebSecurityException
309 db["error"] = "ディレクトリ名に使用できない文字列が含まれています!"
312 db["filelist"] = filer.ls.reverse
313 db["fileinfo"] = filer.lsinfo
314 session["relpath_list"] = filer.relpath_list.join("/")
316 db["info"] = "正常にディレクトリの作成が完了しました。" if db["error"] == ""
320 filer = WebFiler.new(IMGPATH)
321 filer.relpath_list = params["relpath_list"].split("/")
324 filer.cd(params["arg"])
326 db["error"] = "移動先のディレクトリが見つかりません!"
329 db["filelist"] = filer.ls.reverse
330 db["fileinfo"] = filer.lsinfo
331 db["pwd"] = filer.pwd
332 session["relpath_list"] = filer.relpath_list.join("/")
336 filer = WebFiler.new(IMGPATH)
337 filer.relpath_list = params["relpath_list"].split("/")
339 if params["arg"].to_i >= 0
342 params["arg"].to_i.times { |i|
343 movepath << params["relpath_list"].split("/")[i]
345 filer.cd_abs(movepath)
347 db["error"] = "移動先のディレクトリが見つかりません!"
350 db["error"] = "移動先のディレクトリが見つかりません!"
353 db["filelist"] = filer.ls.reverse
354 db["fileinfo"] = filer.lsinfo
355 db["pwd"] = filer.pwd
356 session["relpath_list"] = filer.relpath_list.join("/")
360 filer = WebFiler.new(IMGPATH)
361 filer.relpath_list = params["relpath_list"].split("/")
363 db["filelist"] = filer.ls.reverse
364 db["fileinfo"] = filer.lsinfo
365 db["pwd"] = filer.pwd
366 session["relpath_list"] = filer.relpath_list.join("/")
370 filer = WebFiler.new(IMGPATH)
372 db["filelist"] = filer.ls.reverse
373 db["fileinfo"] = filer.lsinfo
374 db["pwd"] = filer.pwd
375 session["relpath_list"] = filer.relpath_list.join("/")
382 # SESSION変数、パラメータなどを取得します
384 session = CGI::Session.new(cgi)
385 params = Hash[*cgi.params.to_a.map{|k, v| [k, v[0].to_s]}.flatten]
386 params.each { |k, v| params[k] = cgi[k].read if cgi[k].respond_to?(:read) && k != "updata"}
389 if params["mode"] == "logout"
390 session["login"] = nil
391 session["logini"] = nil
392 session["password"] = nil
398 if session["login"] == "true"
399 db = PStore.new("./work/#{session.session_id}_file.dat")
406 Controller.MultiForm(cgi, session, params, db)
410 if session["login"] != "true"
411 # if session["login"] == "true"
412 # セッションが存在しない場合は強制的にエラーページに遷移
413 htmlwriter = HtmlWriter.new("./erbtemp/fileindex.html.erb", binding)
415 htmlwriter = HtmlWriter.new("./erbtemp/filemanager.html.erb", binding)
420 cgi.out{htmlwriter.to_code}
422 # エラーが発生した場合、それを画面に表示します
423 htmlwriter = HtmlWriter.new("./erbtemp/exception.html.erb", binding)
424 cgi.out{ htmlwriter.to_code }
431 # エラーが発生した場合、それを画面に表示します
432 detail = ("%s: %s (%s)\n" %
433 [evar.backtrace[0], evar.message, evar.send('class')]) +
434 evar.backtrace[1..-1].join("\n")
435 puts "content-type: text/html\n\n<plaintext>\n" + detail