シェルcgiでファイルアップロード

なんか無理やり過ぎてユニケージと言って良いのかわからなくなってきた…。

ファイルアップロードを行う。
ブログの様なものを想定し、1記事に複数ファイルをアップロード出来る。
ディレクトリ構成は以下の様な感じ
posts/
┣001/
┃┣post1
┃┣post2
┃┗ files/
┣002/
┃┣post1
┃┗files/

この"files"にファイルをアップロードしていく。
今回はファイルアップ時に画面遷移したくないのでajaxで対応。
(post1が初投稿、post2は更新ファイル。数字が大きい物が最新)

流れはこんな感じ。
1.ajaxでアップロード
2.ddコマンドでファイルをコピー
3.ファイル名を変更
4.不要な行を削除 (?)

1.ajaxでアップロード

jqueryを使ってファイルをアップロード

[up.html]

<form id="frm" method="post" enctype="multipart/form-data">
  <input type="file" name="file" />
  <input type="submit" />
</form>

[up.js]

function up(){
 // formのデータを取得
  formData = new FormData($('#frm'));
  $.ajax({
    url: '/fileup.cgi/001',
    type: 'post',
    data: formData,
    processData: false,
    contentType: false
  });
  // falseを返してsubmitを中断
  return false;
}

urlの"001"はアップロード先の記事のID。
本来は可変にしたいので、mojihameとか使ってIDをはめ込めばよい。

2.ddコマンドでファイルをコピー

[fileup.cgi]

# アップロード先取得
id=$(echo $REQUEST_URI | sed "s/^\/fileup\.cgi\///g")
dir=/posts/${id}/files

# ファイルをコピー
tmp=$(mktemp)
dd bs=${CONTENT_LENGTH} of=$tmp

アップロード先取得では、urlの中から記事のIDを抽出してアップロード先のディレクトリを決めている。(IDは"001"とか"002")
ddコマンドでとりあえずまるごとコピー。

3.ファイル名を変更

ファイル名を受信データから取り出して名前を変える。
[fileup.cgi]

filename=$(awk 'NR==2' ${tmp}                |
           nkf -w -                          |
           grep -o -e "filename=\"\(.*\)\""  |
           sed 's/filename="\(.*\)"/\1/g'    )

2行目に"filename="で始まるファイル名が記載されている箇所があるのでそこから抽出。
ファイル名が日本語だと化けるのでnkfで変換。

4.不要な行を削除 (?)

ここは非常にその場しのぎ的だが、とりあえずメモ。
[fileup.cgi]

# 拡張子取得
ext=${filename##*.}
# 不要行を削除して書き出し
if [ ${ext} = "txt" ]; then
  sed -e '$d;1,4d' ${tmp} |
  sed -e '$d'             |
  nkf -w -                >${dir}/${filename}
else
  sed -e '$d;1,4d' ${tmp} >${dir}/${filename}
fi

1-4行目に"Content-Type"とか"filename="とかいった情報が入っているので削除する。
テキストファイルに関しては最終2行にも不要なものが入っていたので削除。
完全に結果論なので破綻する可能性大だが、とりあえず動けば良いのでこれでオーケー。

全体的にもっと良い書き方があるのだろうけど、シェルスクリプト初心者にはこれが限界。