"""
CGIアプリケーションの基本機能を提供するモジュール。
このモジュールは、`tkApplication` を継承し、CGI環境でのHTTPヘッダ出力、
フォームデータの取得、パスの検証などの機能を追加した `tkApplication_CGI` クラスを提供します。
関連リンク: :doc:`tkapplication_cgi_usage`
"""
import os
import sys
import re
import cgi
import requests
from tklib.tkapplication import tkApplication
[ドキュメント]
class tkApplication_CGI(tkApplication):
"""
CGI環境で動作するアプリケーションの基底クラス。
`tkApplication` を継承し、CGI固有の処理(HTTPヘッダの出力、GET/POSTデータの解析、
フォームデータの取得、パスのセキュリティ検証など)を提供します。
"""
def __init__(self, **args):
"""
tkApplication_CGI クラスのコンストラクタ。
親クラスの初期化を行い、CGIフォームデータを格納するための `cgi.FieldStorage` オブジェクトを初期化します。
:param args: キーワード引数。`tkApplication` のコンストラクタに渡される。
:type args: dict
:returns: None
"""
super().__init__(**args)
self.initialized = False
self.closed = False
self.form = cgi.FieldStorage()
self.update(**args)
def __del__(self):
"""
tkApplication_CGI クラスのデストラクタ。
親クラス `tkApplication` のデストラクタを呼び出します。
:returns: None
"""
super(tkApplication, self).__del__()
def __str__(self):
"""
オブジェクトの文字列表現を返す。
クラスの完全修飾名を返します。
:returns: str: クラスの完全修飾名。
"""
return self.ClassPath()
[ドキュメント]
def init_html(self, charset = 'utf-8', lang = 'ja', extra_headers = None, header_only = False):
"""
HTMLページの初期ヘッダを出力する。
"Content-Type: text/html" ヘッダと基本的なHTML構造
(`<!DOCTYPE html>`, `<html>`, `<head>`, `<body>`)を出力します。
既に初期化されている場合は何もしません。
:param charset: str: HTMLページの文字エンコーディング。デフォルトは 'utf-8'。
:param lang: str: HTMLページの言語。デフォルトは 'ja'。
:param extra_headers: str or None: `head` タグ内に挿入する追加のヘッダ文字列。
:param header_only: bool: `body` タグを出力せず、ヘッダ部分のみを出力するかどうか。
:returns: None
"""
if self.initialized:
return
self.initialized = True
print("Content-Type: text/html")
print("")
print("<!DOCTYPE html>")
print("<html>")
print("<head>")
print(f'<meta http-equiv="Content-Language" content="{lang}">')
print(f'<meta http-equiv="Content-Type" content="text/html; charset={charset}" />')
if extra_headers:
print(extra_headers)
print("</head>")
if not header_only:
print("")
print("<body>")
[ドキュメント]
def end_html(self):
"""
HTMLページの終了タグを出力する。
`</body>` と `</html>` タグを出力します。
既に終了処理が完了している場合は何もしません。
:returns: None
"""
if self.closed:
return
self.closed = True
print("</body>")
print("</html>")
[ドキュメント]
def get_cgi_mode(self):
"""
現在のCGIリクエストメソッド(GETまたはPOST)を文字列で返す。
環境変数 `REQUEST_METHOD` の値に基づいて 'get' または 'post' を返します。
それ以外の場合は空文字列を返します。
:returns: str: 'get', 'post', または空文字列。
"""
if(os.environ['REQUEST_METHOD'] == "GET"):
return 'get'
if(os.environ['REQUEST_METHOD'] == "POST"):
return 'post'
return ''
[ドキュメント]
def get_args(self):
"""
クエリ文字列から引数を辞書形式で取得する。
環境変数 `QUERY_STRING` を解析し、キーと値のペアを辞書として返します。
このメソッドはURLエンコードされた値をデコードしません。
:returns: dict: クエリ文字列の引数を格納した辞書。
"""
line = os.environ.get('QUERY_STRING')
strs = line.split('&')
inf = {}
for s in strs:
a = s.split('=')
inf[a[0]] = a[1]
return inf
[ドキュメント]
def is_get(self):
"""
現在のリクエストがGETメソッドであるかを判定する。
環境変数 `REQUEST_METHOD` が "GET" である場合にTrueを返します。
:returns: bool: リクエストがGETメソッドであればTrue、そうでなければFalse。
"""
if(os.environ['REQUEST_METHOD'] == "GET"):
return True
return False
[ドキュメント]
def is_post(self):
"""
現在のリクエストがPOSTメソッドであるかを判定する。
環境変数 `REQUEST_METHOD` が "POST" である場合にTrueを返します。
:returns: bool: リクエストがPOSTメソッドであればTrue、そうでなければFalse。
"""
if(os.environ['REQUEST_METHOD'] == "POST"):
return True
return False
[ドキュメント]
def getvalue(self, key, defval = None):
"""
フォームデータから指定されたキーの値を取得する。
`cgi.FieldStorage.getvalue()` メソッドをラップし、フォームデータから`key`に対応する値を取得します。
キーが存在しない場合は`defval`を返します。
:param key: str: 取得したいフォームデータのキー。
:param defval: Any or None: キーが見つからなかった場合に返すデフォルト値。デフォルトはNone。
:returns: Any: 指定されたキーの値、またはデフォルト値。
"""
return self.form.getvalue(key, defval)
[ドキュメント]
def getfirst(self, key, defval = None):
"""
フォームデータから指定されたキーの最初の値を取得する。
`cgi.FieldStorage.getfirst()` メソッドをラップし、フォームデータから`key`に対応する最初の値を取得します。
キーが存在しない場合は`defval`を返します。複数の値がある場合でも最初の1つのみを返します。
:param key: str: 取得したいフォームデータのキー。
:param defval: Any or None: キーが見つからなかった場合に返すデフォルト値。デフォルトはNone。
:returns: Any: 指定されたキーの最初の値、またはデフォルト値。
"""
return self.form.getfirst(key, defval)
[ドキュメント]
def validate_path(self, path, keys = 'all'):
"""
提供されたパス文字列がセキュリティ上の問題を含んでいないか検証する。
トップディレクトリへのアクセス(`/`, `\`, `:\\`, `:/`, `//`)、
上位ディレクトリへのアクセス(`..`)、不正な文字(`<`, `>`, `|`)が
含まれていないかをチェックします。`keys` 引数で検証するタイプを指定できます。
:param path: str: 検証対象のパス文字列。
:param keys: str or list: 検証するセキュリティチェックの種類。
'all' (全て), 'top_dir' (トップディレクトリへのアクセス),
'upper_dir' (上位ディレクトリへのアクセス),
'invalid_char' (不正な文字) のいずれか、またはそれらのリスト。
:returns: str: 問題がなければ空文字列。問題がある場合はエラーメッセージ文字列。
"""
if path is None or len(path) == 0:
return ''
if ('all' in keys or 'top_dir' in keys) and (path[0] == '/' or path[0] == '\\' or ':\\' in path or ':/' in path or '//' in path):
return f'Illeagal access to top directory [{path}]'
if ('all' in keys or 'upper_dir' in keys) and '..' in path:
return f'Illeagal access to upper directory [{path}]'
if ('all' in keys or 'invalid_char') in keys and re.search(r'[\<\>\|]', path):
return f'Illeagal characters in [{path}]'
return ''