#!/usr/local/bin/ruby # # $Revision: 1.40 $ # # Copyright (C) 2002,2003 meganecco.org's webmaster # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2, or (at your option) # any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. require 'cgi' require 'uri' require 'net/http' cgi=CGI.new("html4Tr") # configurations class CGI # revision CGI_REV="$Revision: 1.40 $" # max size of upload file (byte) LIMIT=10000000 # mail adr. of administrator MAIL="webmaster@meganecco.org" # this file's name SELF_SCRIPT="index.cgi" # this file's url SELF_URL="http://upload.meganecco.org/" # style sheet STYLESHEET="http://meganecco.org/index.css" # title TITLE="めがねっこ / meganecco - uploader" # CGI name CGI_NAME="uploader" # CGI name CGI_AGENT=CGI_NAME+"/"+CGI_REV.scan(/[\d\.]+/)[0] # directory to store files FILES="files" # log file (this file will be set to the mode 0o200) LOG_FILE="files/.log" # baseurl of stored files FILES_BASEURL="http://upload.meganecco.org/" # full path of jpeginfo JPEGINFO="/usr/bin/jpeginfo" # full path of tar TAR="/bin/tar" # full path of convert CONVERT="/usr/bin/convert" # comments COMMENTS=[ "外部からのアクセスがしばらくないものは削除されます.", "適宜管理人による削除が行なわれる場合があります.", "#{LIMIT}byte 以上の file は upload できません.", "file 名は適当に付けられます.", "拡張子はリストにあるものから選択するか,その左の「その他の拡張子」を利用して指定してください.", "「その他の拡張子」で利用できる文字は a-z と . (だたし /^[a-z]+[a-z\.]*[a-z]+$/)で,8文字までです.", "jpg の場合のみリサイズ(縮小のみ)が可能です.アクペクト比を保ったまま指定サイズに納まるように縮小します.", "リサイズする場合はラジオボタンで選択するか,custom を選択してサイズを入力してください", "サイズを入力する場合は 16x16 以上でなければなりません", "URL による入力が可能になりました(20030121).", "URL による入力により取得しようとしているファイルが再配布可能なものかを必ず確認して,利用者の責任に於て利用してください.", "URL による入力は FILE の UPLOAD よりも優先されます.", "URL による入力を行なった場合拡張子は content-type により判断されます.", "サポートする content-type は image/jpeg(.jpg),image/png(.png),image/gif(.gif),^text/html(.html),^text(.txt) のみです.", "これ以外の content-type は拡張子 .bin になります.", "image/jpeg の場合はリサイズも可能です.", ] # extensions EXTENSIONS=["jpg","avi","png","mpg","txt","deb","gif"] # sizes SIZES={ "VGA"=>[640,480], "SVGA"=>[800,600], "XGA"=>[1024,768], "SXGA"=>[1280,1024], "UXGA"=>[1600,1200], } end # end of configurations class Dir def Dir.unlink_recursive(path) Dir.open(path).each do |i| next if i=="." or i==".." f=path+"/"+i if File.directory?(f) Dir.unlink_recursive(f) else File.unlink(f) end end Dir.unlink(path) end end class CGI def my_out(b) out({"charset"=>"euc-jp"}){ r=html{ head{ link({"rel"=>"stylesheet","href"=>STYLESHEET,"type"=>"text/css"})+ link({"rev"=>"made","href"=>"mailto:#{MAIL}"})+title{TITLE} }+body{ h1{CGI_NAME}+b+ p({"CLASS"=>"center"}){a(SELF_URL){CGI_NAME}}+ p({"CLASS"=>"center"}){a("http://meganecco.org/"){"meganecco.org"}}+ address{"all about this page =>"+ a("mailto:#{MAIL}"){"webmaster (E-mail:#{MAIL})"}} } } begin CGI.pretty(r) rescue r.gsub(/>\n<") end } end def source_page; out("text/plain"){open(SELF_SCRIPT).read} end def top_page c=[];r="" SIZES.sort{|a,b| (a[1][0]*a[1][1])<=>(b[1][0]*b[1][1])}.each{|i| c<<"[\"#{i[0]}\",\"#{i[0]}(#{i[1][0]}x#{i[1][1]})\"]" } eval "r=radio_group(\"resize\",[\"none\",true],#{c*","},\"custom\")" my_out multipart_form(SELF_URL){ table{ ""+ tr{td{"ファイル:"}+td{file_field("uploaded_file",40)}}+ tr{td{"URL入力:"}+td{text_field("url")}}+ tr{td{"拡張子:"}+ td{popup_menu({"NAME" => "name","VALUES"=>EXTENSIONS})+ "その他の拡張子:"+text_field("custom_ext") } }+ tr{td{"リサイズ:"}+td{r}}+ tr{td{"はば:"}+td{text_field("width")}}+ tr{td{"高さ:"}+td{text_field("height")}}+ tr{td{"tgz mode:"}+td{checkbox("tgz")}}+ tr{td{""}+td{submit("Submit")+reset("Reset")}} } }+ ul{ r=""; COMMENTS.each{|i| r+=li{i}} r+=li{a("#{SELF_URL}?cmd=src"){"source"}+ " ("+a("http://www.ruby-lang.org/"){"Ruby"}+ " Script) - やるきなし(かなり)" } } end def log(s) fp=open(LOG_FILE,"a") fp.flock(File::LOCK_EX) fp.write("#{@time.to_i} #{s}\n") fp.close File.chmod(0o200,LOG_FILE) end def access_log log("#{ENV["REMOTE_HOST"]}(#{ENV["REMOTE_ADDR"]})") end def check if not EXTENSIONS.include?(@ext) if @ext=~/^[a-z0-9]+[a-z0-9\.]*[a-z0-9]+$/ if @ext.size>=8 my_out(p{"given 拡張子 is invalid: #{@ext}"}); exit end else my_out(p{"given 拡張子 is invalid: #{@ext}"}); exit end end if @size>LIMIT my_out(p{"file size is too large: #{@size}byte"}); exit end if @size==0 my_out(p{"error: file size is zero"}); exit end end def get_jpeg_size(filename) return [0,0] if not @ext=="jpg" c=`#{JPEGINFO} #{filename}` return [0,0] if c.include?("Not a JPEG file") t=c.scan(/(\d+)\s+x\s+(\d+)/)[0] width=t[0].to_i height=t[1].to_i return [width,height] end def make_info(url,size,width,height) r="" if @ext=="jpg" if width*height==0 r+="size: #{size}byte (Maybe not a JPEG file)"+br else r+="size: #{size}byte (#{width}x#{height})"+br end else r+="size: #{size}byte"+br end r+="url:"+a(url){url}+br if @ext=="jpg" or @ext=="png" or @ext=="gif" r+=CGI::escapeHTML("for rwiki: ((<\"img:#{url}\">))")+br end r+=CGI::escapeHTML("for rwiki: (())")+br r+=CGI::escapeHTML("for rwiki: ((<.|URL:#{url}>))")+br return r end ## parameter check def param_check @param={} preread_params=["name","url","resize","width","height","custom_ext","tgz"] params=["cmd","uploaded_file"]+preread_params params.each do |i| if not self.params[i].empty? @param[i]=self.params[i][0] end end preread_params.each do |i| if @param[i]!=nil if @param[i].size!=0 @param[i]=@param[i].read.strip else @param[i]="" end else @param[i]="" end end end def make_filename filename=FILES+"/"+Time.now.to_f.to_s+"."+@ext while File.exist?(filename) filename=FILES+"/"+Time.now.to_f.to_s+"."+@ext end return filename end def make_dirname filename=FILES+"/"+Time.now.to_f.to_s while File.exist?(filename) filename=FILES+"/"+Time.now.to_f.to_s end return filename end def save_file(got_body) filename=make_filename f=open("#{filename}","w") f.write(got_body) f.close log("Saved to:#{filename}") return filename end def resize_image(orig_file) r="" log("Resize:#{@resize*"x"}") resize_filename=make_filename s="#{@resize[0]}x#{@resize[1]}" command="#{CONVERT} -size #{s} #{orig_file} -resize #{s} #{resize_filename}" system command r+="resize しました(指定: #{s})"+br log("Saved to:#{resize_filename}") width,height=get_jpeg_size("#{resize_filename}") size=FileTest::size("#{resize_filename}") url=FILES_BASEURL+resize_filename r+=make_info(url,size,width,height) return r end def expand_dir(dir) r=[] Dir.new(dir).each do |i| next if i=="." or i==".." f=dir+"/"+i if File.directory?(f) r=r+expand_dir(f) else r<=16 and @resize[1]>=16 end ## main routine def main @time=Time.now param_check access_log if @param["cmd"]=="src" source_page; exit end if @param["uploaded_file"]==nil or @param["name"]==nil top_page; exit end path=@param["url"] if (not path.empty?) ### URL Input Mode begin uri=URI.parse(path) # raise if it's not http raise if uri.scheme!="http" # use proxy if available p=ENV["http_proxy"] if p!=nil p=URI.parse(p) $proxy_addr=p.host $proxy_port=p.port end got_body=""; got_type="" Net::HTTP::Proxy($proxy_addr,$proxy_port).new(uri.host,uri.port).start do |h| res=h.get(uri.request_uri,{"user-agent"=>CGI_AGENT}) got_body=res.body got_type=res['content-type'] end body=p{path}+p{got_body.size}+p{got_type} if got_type=="image/gif" @ext="gif" elsif got_type=="image/png" @ext="png" elsif got_type=="image/jpeg" @ext="jpg" elsif got_type=~/^text\/html/ @ext="html" else if got_type=~/~text/ @ext="txt" else @ext="bin" end end log("URL:#{path} (#{got_type})") rescue log("URL(error):#{path}") my_out(p{"error: can't get the url: #{path}"}); exit end else ### File Upload Mode if @param["custom_ext"].empty? @ext=@param["name"] else @ext=@param["custom_ext"] end if @param["tgz"]=="on" @ext="tar.gz" end got_body=@param["uploaded_file"].read got_body="" if got_body==nil log("File:#{got_body.size}") end ### Resize Parameter Check rs=@param["resize"] if rs=="custom" @resize=[@param["width"].to_i,@param["height"].to_i] for i in 0..1 if @resize[i]==0 @resize[i]=nil end end elsif SIZES[rs]!=nil @resize=SIZES[rs] else ## "none" @resize=[nil,nil] end ### Input Data Check @size=got_body.size check ### Save File @filename=save_file(got_body) width,height=get_jpeg_size("#{@filename}") size=@size url=FILES_BASEURL+@filename orig_file_info=make_info(url,size,width,height) ### Do Resize if resize?(width,height) resize_info=resize_image("#{@filename}") else resize_info="" end ### Output Html my_out body=p{ r="" r+=p{orig_file_info} r+=p{resize_info} if @param["tgz"]=="on" dir=make_dirname Dir.mkdir(dir) tar_res=system("#{TAR} zxvf #{@filename} -C #{dir} > /dev/null 2>&1 ") if tar_res log("expaneded to:#{dir}") h=expand_dir(dir) r+=p{"展開しました"} dir_info="" expand_dir(dir).each{|i| of=i.scan(/^#{dir}\/(.*)$/).flatten.last dir_info+=of+br } r+=p{dir_info} expand_dir(dir).each{|i| log("tar input: #{i}") begin @ext=i.scan(/^.*\.([^\.]*)$/).flatten.last.downcase @ext="jpg" if @ext=="jpeg" if @ext!="jpg" log("skip: #{i}") next end @filename=save_file(open(i).read) width,height=get_jpeg_size("#{@filename}") size=@size url=FILES_BASEURL+@filename orig_file_info=make_info(url,size,width,height) if resize?(width,height) resize_info=resize_image("#{@filename}") else resize_info="" end of=i.scan(/^#{dir}\/(.*)$/).flatten.last r+=p{"#{of}->#{url}"} r+=p{orig_file_info} r+=p{resize_info} rescue r+=p{"なにかエラーが発生しました.とほほ."} end } Dir.unlink_recursive(dir) else r+="false"+br end end r } end end cgi.main