http://www.mbx.jp/test/index.cgi
#! /usr/local/bin/ruby -EUTF-8
# -*- mode:ruby; coding:utf-8 -*-

#----------------#
# 外部ライブラリ #
#----------------#
require 'fileutils'
require 'cgi'

#------------------#
# 表示に関する設定 #
#------------------#
CGI.accept_charset=("UTF-8")
c = CGI.new

SITE_TITLE       = CGI.escapeHTML(c['SITE_TITLE'])
HOME_PAGE        = CGI.escapeHTML(c['HOME_PAGE'])

BODY_BGCOLOR     = CGI.escapeHTML(c['BODY_BGCOLOR'])
BODY_TEXT_COLOR  = CGI.escapeHTML(c['BODY_TEXT_COLOR'])
BASEFONT_SIZE    = CGI.escapeHTML(c['BASEFONT_SIZE'])

PAGE_TITLE       = CGI.escapeHTML(c['PAGE_TITLE'])
TITLE_FONT_COLOR = CGI.escapeHTML(c['TITLE_FONT_COLOR'])
TITLE_FONT_SIZE  = CGI.escapeHTML(c['TITLE_FONT_SIZE'])

NAME_HEADING     = CGI.escapeHTML(c['NAME_HEADING'])
NAME_SIZE        = CGI.escapeHTML(c['NAME_SIZE'])
NAME_TEXT        = CGI.escapeHTML(c['NAME_TEXT'])
NAME_NOTES       = "             "

LINK_HEADING     = CGI.escapeHTML(c['LINK_HEADING'])
LINK_SIZE        = CGI.escapeHTML(c['LINK_SIZE'])
LINK_TEXT        = CGI.escapeHTML(c['LINK_TEXT'])
LINK_NOTES       = "             "

MESSAGE_HEADING  = CGI.escapeHTML(c['MESSAGE_HEADING'])
MESSAGE_COLS     = CGI.escapeHTML(c['MESSAGE_COLS'])
MESSAGE_ROWS     = CGI.escapeHTML(c['MESSAGE_ROWS'])
MESSAGE_TEXT     = CGI.escapeHTML(c['MESSAGE_TEXT'])
MESSAGE_NOTES    = "             "

PREFORMATTED     = CGI.escapeHTML(c['PREFORMATTED'])

#------------------#
# 制御に関する設定 #
#------------------#
SUBMIT           = CGI.escapeHTML(c['SUBMIT'])
UNIQUE_ID        = ENV['UNIQUE_ID']
CURRENT_PAGE     = CGI.escapeHTML(c['CURRENT_PAGE'])
HTTP_ERROR       = "Status: 403 Forbidden\nContent-type: text/html\n\n"

FORM_ACTION      = "./../"
POST_BOX         = "./../post_box"
WORK_DIR         = "#{POST_BOX}/#{c.remote_addr}"
WORK_FILE        = "#{WORK_DIR}/#{UNIQUE_ID}.txt"

REGEX_URL        = "https?:\/\/[-_.!~*A-Z0-9;\/?:@&=+$,%#]+"
REGEX_MAIL       = ".{1,64}@[A-Z0-9._-]{4,253}"

#------------#
# 国民の祝日 #
#------------#
module TimeEx
   refine Time do
      def wnum
         return ((self.day - 1) / 7 + 1) * 10 + self.wday
      end
      def holiday
         return nil if self < Time.new(1948,7,20)
         y = self.year
         m = self.month
         d = self.day
         soler_frac = 0.2421896875
         vernal_equinox   = (20.8431 + soler_frac *(y-1980)).to_i - (y-1980)/4
         autumnal_equinox = (23.2488 + soler_frac *(y-1980)).to_i - (y-1980)/4
         case m
         when 1
            return "元日" if d == 1
            if y < 2000 then
               return "成人の日" if d == 15
            else
               return "成人の日" if self.wnum == 21
            end
         when 2
            return "建国記念の日" if y >= 1967 && d == 11
            return "天皇誕生日" if y >= 2020 && d == 23
            return "昭和天皇の大喪の礼" if y == 1989 && d == 24
         when 3
            return "春分の日" if d == vernal_equinox
         when 4
            return "皇太子昭仁親王の結婚の儀" if y == 1959 && d == 10
            return "国民の休日" if y == 2019 && d == 30
            if d == 29 then
               if y < 1989 then
                  return "天皇誕生日"
               elsif y < 2007 then
                  return "みどりの日"
               else
                  return "昭和の日"
               end
            end
         when 5
            return "即位の日" if y == 2019 && d == 1
            return "国民の休日" if y == 2019 && d == 2
            return "憲法記念日" if d == 3
            if d == 4 then
               if y < 2007 then
                  return "国民の休日" if y >= 1986 && self.wday >= 2
               else
                  return "みどりの日"
               end
            end
            return "こどもの日" if d == 5
         when 6
            return "皇太子徳仁親王の結婚の儀" if y == 1993 && d == 9
         when 7
            if y < 2003 then
               return "海の日" if y >= 1996 && d == 20
            else
               if y == 2020 || y == 2021 then
                  return "海の日" if y == 2020 && d == 23
                  return "海の日" if y == 2021 && d == 22
                  return "スポーツの日" if y == 2020 && d == 24
                  return "スポーツの日" if y == 2021 && d == 23
               else
                  return "海の日" if self.wnum == 31
               end
            end
         when 8
            if y == 2020 || y == 2021 then
               return "山の日" if y == 2020 && d == 10
               return "山の日" if y == 2021 && d == 8
            else
               return "山の日" if y >= 2016 && d == 11
            end
         when 9
            return "秋分の日" if d == autumnal_equinox
            if y < 2003 then
               return "敬老の日" if y >= 1966 && d == 15
            else
               if self.wnum == 31 then
                  return "敬老の日"
               else
                  return "国民の休日" if self.wday == 2 && d == autumnal_equinox - 1
               end
            end
         when 10
            return "即位礼正殿の儀" if y == 2019 && d == 22
            if y < 2020 then
               if y < 2000 then
                  return "体育の日" if y >= 1966 && d == 10
               else
                  return "体育の日" if self.wnum == 21
               end
            else
               return "スポーツの日" if y >= 2022 && self.wnum == 21
            end
         when 11         
            return "文化の日" if d == 3
            return "即位礼正殿の儀" if y == 1990 && d == 12
            return "勤労感謝の日" if d == 23
         when 12
            if y < 2020 then
               return "天皇誕生日" if y >= 1989 && d == 23
            end
         end
         case self.wday
         when 1
            return "振替休日" if self >= Time.new(1973,4,12) && (self-60*60*24).holiday
         when 2, 3
            return "振替休日" if y >= 2007 && m == 5 && d == 6
         end
         return nil
      end
   end
end
using TimeEx

#--------#
# 前処理 #
#--------#
if SUBMIT == " 確認(S) " then
   #----------------------------#
   # 必須項目の入力漏れチェック #
   #----------------------------#
   DISABLED = ""
   nametext = NAME_TEXT.strip
   linktext = LINK_TEXT.strip
   messagetext = MESSAGE_TEXT.strip

   if nametext.empty? then
      DISABLED = "disabled"
      NAME_NOTES = "<font color=\"\#ff0000\"><b>未入力です</b></font>"
      nametext = " - - - ERROR - - - "
   end

   if messagetext.empty? then
      DISABLED = "disabled"
      MESSAGE_NOTES = "<font color=\"\#ff0000\"><b>未入力です</b></font>"
      messagetext = "\n - - - ERROR - - - \n"
   else
      messagetext.gsub!(/(&lt;|&gt;|&#39;|&quot;)/i){ |match| "\e#{match}" }
      messagetext.gsub!(/(#{REGEX_URL})/i){ |match| "<a href=\"#{match}\" target=\"_top\">#{match}<\/a>" }
      messagetext.gsub!(/\e/, "")
   end

   #--------------------------------#
   # ヘッドラインにリンクを設定する #
   #--------------------------------#
   headline = "<font color=\"\#ff0000\"><b>"
   if linktext.empty? then
      headline << nametext
   elsif linktext.match(/\A#{REGEX_URL}\z/i) then
      headline << "<a href=\"#{linktext}\" target=\"_top\">#{nametext}</a>"
   elsif linktext.match(/\A#{REGEX_MAIL}\z/i) then
      headline << "<a href=\"mailto:#{linktext}\">#{nametext}</a>"
   else
      headline << nametext
      LINK_NOTES = "<font color=\"\#ff0000\"><b> e.g. 〜@hoge.jp, http://fuga.com/〜</b></font>"
      DISABLED = "disabled"
   end
   headline << "</b></font>\n"

   #----------------------------------#
   # ヘッドラインに投稿日時を追加する #
   #----------------------------------#
   week = ["(日)","(月)","(火)","(水)","(木)","(金)","(土)"]
   t = Time.now
   if t.holiday then
      week[t.wday] = "<font color=\"#ff0000\">#{week[t.wday]}#{t.holiday}</font>"
   else
      week[0] = "<font color=\"#ff0000\">#{week[0]}</font>"
      week[6] = "<font color=\"#0000ff\">#{week[6]}</font>"
   end
   headline << t.strftime("%Y/%m/%d#{week[t.wday]} %-H:%M:%S")

   #----------------------#
   # プレビューを作成する #
   #----------------------#
   preview = headline
   preview << "<blockquote>\n"
   if PREFORMATTED == "checked" then
      preview << "<pre>\n#{messagetext}\n</pre>"
   else
      preview << messagetext.gsub(/\R/, "<br>\n")
   end
   preview << "\n</blockquote><hr>\n<!--End of Article-->\n\n"

   #------------------------------------------------#
   # エラーがなければプレビューをファイルに保存する #
   #------------------------------------------------#
   if DISABLED.empty? then
      FileUtils.mkdir_p(WORK_DIR, :mode => 0700)
      File.open(WORK_FILE, mode = "w", perm = 0600){ |f|
         f.puts preview
      }
   end
   NAVIGATION = "[ <a href=\"#{HOME_PAGE}\" target=\"_top\">Home</a> ]"

   #------------#
   # HTMLの出力 #
   #------------#
   puts c.header
   print <<"EOS"
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html lang="ja">
   <head>
      <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
      <title>#{SITE_TITLE}</title>
      <link rel="canonical" href="#{HOME_PAGE}">
   </head>
   <body bgcolor="#{BODY_BGCOLOR}" text="#{BODY_TEXT_COLOR}">
      <basefont size="#{BASEFONT_SIZE}">
      <p>#{NAVIGATION}</p>
      <div align="center">
         <font size="#{TITLE_FONT_SIZE}" color="#{TITLE_FONT_COLOR}">
            <b>#{PAGE_TITLE}</b>
         </font>
      </div>
      <hr>
      <form method="post" action="#{FORM_ACTION}">
         <table border="0" summary="Posted column">
            <tr>
               <td>#{NAME_HEADING}</td>
               <td>
                  <input type="hidden" name="NAME_HEADING" value="#{NAME_HEADING}">
                  <input type="hidden" name="NAME_SIZE" value="#{NAME_SIZE}">
                  <input type="text" name="NAME_TXT" SIZE="#{NAME_SIZE}" value="#{NAME_TEXT}" disabled>
                  <input type="hidden" name="NAME_TEXT" value="#{NAME_TEXT}">
                  <small>#{NAME_NOTES}</small><br>
               </td>
            </tr>
            <tr>
               <td>#{LINK_HEADING}</td>
               <td>
                  <input type="hidden" name="LINK_HEADING" value="#{LINK_HEADING}">
                  <input type="hidden" name="LINK_SIZE" value="#{LINK_SIZE}">
                  <input type="text" name="LINK_TXT" SIZE="#{LINK_SIZE}" value="#{LINK_TEXT}" disabled>
                  <input type="hidden" name="LINK_TEXT" value="#{LINK_TEXT}">
                  <small>#{LINK_NOTES}</small><br>
               </td>
            </tr>
            <tr>
               <td colspan="2">#{MESSAGE_HEADING}<small>#{MESSAGE_NOTES}</small></td>
            </tr>
            <tr>
               <td colspan="2">
                  <input type="hidden" name="MESSAGE_HEADING" value="#{MESSAGE_HEADING}">
                  <input type="hidden" name="MESSAGE_COLS" value="#{MESSAGE_COLS}">
                  <input type="hidden" name="MESSAGE_ROWS" value="#{MESSAGE_ROWS}">
                  <textarea cols="#{MESSAGE_COLS}" rows="#{MESSAGE_ROWS}" name="MESSAGE_TXT" disabled>#{MESSAGE_TEXT}</textarea>
                  <input type="hidden" name="MESSAGE_TEXT" value="#{MESSAGE_TEXT}">
                  <input type="checkbox" name="PREFORMATTED" value="checked" #{PREFORMATTED} disabled>整形済み(P)
                  <input type="hidden" name="PREFORMATTED" value="#{PREFORMATTED}">
               </td>
            </tr>
         </table>
         <p>
            <input type="hidden" name="UNIQUE_ID" value="#{UNIQUE_ID}">
            <input type="submit" name="SUBMIT" value=" 確認(S) " #{DISABLED} accesskey="s" tabindex="2">(書き込む)
            <input type="submit" name="SUBMIT" value=" 戻る(B) " accesskey="b" tabindex="3">(修正する)
         </p>
      </form>
      <hr><hr>これはプレビューです。<hr><hr>#{preview}<hr>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
      <br><br><br><br><br><br><br><br><br><br><br><br><br><br><br>
   </body>
</html>
EOS
else
   print HTTP_ERROR
end