Ruby CGI でファイルアップロードを実装する・オレオレエクスプローラを作ってみた

CGIScriptMarket.com というサイトで配布されていた、XplorerWEB EDITOR という CGI をよく使っていた。テキストファイルを開いて編集したり、アップロードしたりできる CGI だった。

この CGI は Perl 製で、時代的にも jcode.pl なんかを使っていて、今となっては古さが目立っていた。また、自分でも似たような CGI を作ってみたいというスキル習得の目的から、今回は Ruby CGI でファイルアップロードを実現するプログラムを書いてみた。

参考にしたのは以下あたり。

まず、ファイルアップロード欄は次のように実装する。

<form action="./upload.rb" method="POST" enctype="multipart/form-data">
  <input type="file"   name="file">
  <input type="text"   name="text" value="">
  <input type="submit"             value="Upload">
</form>

enctype="multipart/form-data" を指定することに留意。

ファイルを受信して保存する Ruby CGI スクリプトは次のような感じで。

#!/usr/bin/ruby

require 'cgi'        # CGI
require 'fileutils'  # File
require 'pathname'   # Pathname

$cgi = CGI.new

# ファイルの情報を取得する
upload_file = $cgi.params['file'][0]

# アップロードされたファイルからファイル名を取得する : `FILE-NAME.txt` のような文字列が取れることになる
file_name = upload_file.original_filename.split(/(\\|\/)/)[-1]

# ファイル保存先のフルパス文字列を作る : `/PATH/TO/home/sub-directory/FILE_NAME.txt` となる
target_path = Pathname.new('/PATH/TO/home').join('sub-directory', file_name).cleanpath.to_s

# ファイルをアップロード (書き込み) する
File.open(target_path, 'w') do |file|
  file.binmode
  file.write(upload_file.read)
end

# その他、フォーム送信された情報を取得してみる
text = $cgi.params['text'][0].read

# レスポンスとして HTML を表示する
print(<<"EOL")
Content-Type: text/html; charset=UTF-8

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="UTF-8">
    <title>Result</title>
  </head>
  <body>
    <p>アップロードしました</p>
    <p>ファイル名 : #{file_name}</p>
    <p>保存先フルパス : #{target_path}</p>
    <p>テキスト : #{text}</p>
  </body>
</html>
EOL

適宜、リクエストメソッドが POST かどうかとか、アップロード先ディレクトリやファイル名がおかしくないかとか、チェックを設けよう。


以前作った、Node.js CGI Explorer という CGI がある。当初はコレを拡張してファイルアップロード機能を実装しようと思っていたのだが、Node.js CGI でファイルを受け取る実装が面倒臭そうだったので、CGI モジュールを持っていて実装がやりやすそうな、Ruby で実装することにした。

シングル CGI ファイルにすると配備が楽ではあるが、リクエスト種別を判定してレスポンスを変えていく実装が肥大化して辛くなってくる。じゃあもう機能別に一つずつ CGI ファイルがあっても良いかな、とか思って、Neo's CGI Explorer なるプロジェクトを始めてみた。

今の所、エクスプローラ部分は前述のスクリプトをベースにした Node.js 製で、ファイルアップロード機能のみ Ruby CGI で実装している。フロントエンドはナンチャッテ SPA で結構強引。

ファイルの作成・リネーム・移動・コピー・削除なども実装してみた。1ファイル1機能で、API 的に CGI ファイルを増やしていった感じ。fsmkdir()unlink() やらをただ呼んでるだけ。

イマイチなのは、ディレクトリを再帰的にコピーする機能がまだないのと、.gitignore のような拡張子のないテキストファイルを編集できないところ。どういうファイルを「テキストファイル」とみなすか、というところがさばききれていない。

ま、とりあえず最低限欲しかったモノは作れたかなー。