ディレクトリの参照

戻る

URL上のパス(仮想ディレクトリ)から、実際のディレクトリ情報を取得する方法である。CGIでファイルのリストを出力するような場合に、GETメソッドでターゲットのパスをクエリーとして渡すような場合に応用できる。CGIを動かすサイトのディレクトリ構造を把握しているのならば、プログラム中で固定的な変換をしても構わないが、仮想ディレクトリをいくつか持っている場合などはメンテナンスも煩雑になってしまうため、これを避ける方法を取りたい。また、他のサーバに持ち込んだ場合(そんなケースは滅多に無いかもしれないが)にも、この方法で対応できるわけだ。

相対パスに関しては、CGIプログラムのパス情報を環境変数から持ってくることで解決できるはずだ。CGIの仮想ディレクトリは ENVIRON("PATH_INFO")や ENVIRON("URL")で拾え、実ディレクトリは ENVIRON("PATH_TRANSLATED")で拾える。これらを用いて、下記のステップでターゲットディレクトリを導ける。

  1. 相対パスの判定 〜 パスの最初の文字が「/」ではなければ相対パス
  2. 絶対パスの作成 〜 CGI自身のパスと上記のパス文字列を結合し、ピリオド「.」を処理
  3. 実ディレクトリの作成 〜 CGIのディレクトリ情報を使いつつ、絶対パスから変換

ピリオド「.」の処理では、単独のピリオドは削除、連続のピリオドは1階層上のディレクトリを示すように変更を行う。この時に注意すべき事として、WEBで公開していないディレクトリが指定された場合の処理があげられる。危険なケースは、パスがルートよりも上層になってしまう場合である。ターゲットパスとして「../../」が指定されると、CGI格納ディレクトリの2階層上を示すことになり、何の処理も行わなければ、デフォルト状態ではハードディスクのルートになってしまう。例えば「../../Winnt/system32」がどこを指すか、おわかりだろう。

絶対ディレクトリの解決方法は、レジストリにあるディレクトリのマッピング情報を使うことで可能になる。上記のステップ4についてもこの方法で対応することができる。レジストリをいじるのは危険が伴うから注意して欲しい。ここでは読み込みしか行わないから、何かミスをしない限りは問題は無いと思われるが。

実際のプログラム例を示す。例によって(?)APIを使う。宣言部と関数部を一気に書いておく。この例示では最上層のパスのみを文字列引数として渡すことで、実ディレクトリを返す。つまり、「/CGI」を渡すと「c:\cgi」を返すような仕組である。WWWルートディレクトリは、「/」に対応するようになっている。マッピング情報はレジストリの HKEY_LOCAL_MACHINE下、System\CurrentControlSet\Services\W3SVC\Parameters\Virtual Rootsに存在する。値としては3つのパラメータがカンマ「,」で区切られた文字列となっているが、ディレクトリはこのうちの最初の「,」までである。3番目のパラメータはアクセス権の設定情報だ。(Regeditで一度見てみると良い)


レジストリ関連の宣言部


Private Declare Function RegOpenKey Lib "advapL32.dll" Alias "RegOpenKeyA" _
    (ByVal hKey As Long, ByVal lpSubKey As String, phkResult As Long) As Long
Private Declare Function RegQueryValueEx Lib "advapL32.dll" Alias "RegQueryValueExA" _
    (ByVal hKey As Long, ByVal lpValueName As String, ByVal lpReserved As Long, _
     lpType As Long, lpData As Any, lpcbData As Long) As Long
Private Declare Function RegCloseKey Lib "advapL32.dll" (ByVal hKey As Long) As Long

Const HKEY_LOCAL_MACHINE = &H80000002

WWWパスから、実ディレクトリを取得


Public Function WebPathToDir(WebPath As String) As String

    Dim I As Integer
    Dim S As String
    Dim hnd As Long             'キーハンドル
    Dim rtype As Long           'タイプ
    Dim rlen As Long            'バッファの長さ
    Dim str As String * 1024    'バッファ
    Dim regret As Long          '戻り値
    
    Const REG_PATH = "System\CurrentControlSet\Services\W3SVC\Parameters\Virtual Roots"
    
    WebPathToDir = ""
    If RegOpenKey(HKEY_LOCAL_MACHINE, REG_PATH, hnd) = 0 Then
        rlen = 1024: str = Space(rlen)
        If RegQueryValueEx(hnd, nm, 0, rtype, ByVal str, rlen) = 0 Then
            WebPathToDir = Left(str, InStr(str, Chr(0)) - 1)
        End If
    End If

    If WebPathToDir <> "" Then
        WebPathToDir = Left(WebPathToDir, InStr(WebPathToDir, ",") - 1)
    End If

End Function

実はあまり真面目に書いていないので、くれぐれも検証して頂くように願いたい。レジストリは読み込みのみなので、デバッグモードで動作を確認すれば良いだろう。なお、ここで使っているAPIはNTと95に共通するものである。レジストリを一覧的に取り出すためのAPIは95とNTでは異なったものとなる。一覧を取り出してマッチングを確認していく処理も可能であろう。いずれにせよ、上記の通り、レジストリ格納場所を知っておき、これを取り出す手段を作れば良いのだ。(レジストリのいじり方は、どこか別のサイトで詳しく説明してくれていると思うよ)