'websql' スクリプト 強化版

 今度の 'websql' スクリプトは、データベースへの接続情報などを全て XMLファイルに外出しして、汎用性を高めています。 このXMLファイルの解析には、PHPのXML関数を使っています。

<?php
/**
 * websql.php
 *
 * POST変数
 *
 * querydef ... 検索するデータベース等を記述したXMLファイルの主ファイル名。
 *   この名前に拡張子.xmlをつけたファイルを、設定ファイルとしてロードします。
 * その中には、ルートタグ「querydef」の下に、次の要素を記述できます。
 *
 * database ... 接続先のデータベース
 * user ... 接続するユーザ
 * password ... 接続するユーザのパスワード
 * query ... SQL文。プレースホルダーを必要に応じて:p1〜:p10の10個まで
 *   指定できます。
 * output-filename-format ... 出力ファイル名のフォーマット。
 *   デフォルトは 'result.txt'。
 * header ... 見出し文字列を|で区切ったもの。
 *
 * p1,p2,p3,p4,p5 ... p10 ...
 *   (オプション)プレースホルダーに対応するパラメータ値。
 *
 * 2002/12/20
 * 2003/01/18
 */
// データファイルを出力するディレクトリの、このスクリプトがある
// ディレクトリからの相対パス
$workdirrelpath = "work";

$q=addslashes($_POST["querydef"]);
$dirname = dirname($_SERVER[SCRIPT_FILENAME]);
$filename = "${dirname}/${q}.xml";
$OUTPUTFILEDIR = "${dirname}/${workdirrelpath}";
header("Content-Type:text/html");
?>
<html>
<body bgcolor="white">

<?php
$curName = "";
$querydef = array();

/**
 * 作業ディレクトリのファイルを検索し、作成から一定日経っているファイルを
 * 削除します。
 */
function clearWorkDir(){
  global $OUTPUTFILEDIR;

  if(! ($indir = opendir($OUTPUTFILEDIR))){
    die("ERROR 50<br>");
  }
  while($entry = readdir($indir)){
    $filename = $OUTPUTFILEDIR . "/" . $entry;
    if(is_file($filename)){
      $mtime = filemtime($filename);
      if($mtime < time() - 7 * 24 * 60 * 60){
        //print "古いファイル $filename を削除します。<br>";
        unlink($filename);
      }
    }
  }
  closedir($indir);
}

/**
 * XML文書の要素開始ハンドラです。
 */
function startElement($parser, $name, $attrs){
  global $curName;
  global $querydef;
  //print "{" . $name . "}<br>";
  //タグは大文字に変換されます。
  if($name == "DATABASE" || $name == "USER" || $name == "PASSWORD" ||
     $name == "QUERY" || $name == "OUTPUT-FILENAME-FORMAT" ||
     $name == "HEADER"){
    $curName = $name;
    $querydef[$curName] = "";
  }
}

/**
 * XML文書の要素終了ハンドラです。
 */
function endElement($parser, $name){
  global $curName;
  global $querydef;

  if($curName != ""){
    // 最後に前後の空白・改行文字を削除します。
    $querydef[$curName] = trim($querydef[$curName]);
    $curName = "";
  }
}

/**
 * XML文書の文字データハンドラです。
 */
function handleCharData($parser, $data){
  global $curName;
  global $querydef;

  if($curName != ""){
    // 一応、改行文字をつけます。
    $querydef[$curName] .= trim($data) . "\n";
  }
}

/**
 * 引数で指定したファイルをXML文書として読み、プロパティを取得します。
 */
function readXML($filename){
  $parser = xml_parser_create();
  xml_set_element_handler($parser, "startElement", "endElement");
  xml_set_character_data_handler($parser, "handleCharData");
  if (!($fp = fopen($filename, "r"))) {
    die("could not open XML input");
  }
  while ($data = fread($fp, 4096)) {
    if (!xml_parse($parser, $data, feof($fp))) {
      die(sprintf("XML error: %s at line %d",
        xml_error_string(xml_get_error_code($parser)),
        xml_get_current_line_number($parser)));
    }
  }
  fclose($fp);
  xml_parser_free($parser);
}


readXML($filename);
clearWorkDir();

if(! empty($_POST["p1"])){ $p1 = $_POST["p1"]; }
if(! empty($_POST["p2"])){ $p2 = $_POST["p2"]; }
if(! empty($_POST["p3"])){ $p3 = $_POST["p3"]; }
if(! empty($_POST["p4"])){ $p4 = $_POST["p4"]; }
if(! empty($_POST["p5"])){ $p5 = $_POST["p5"]; }
if(! empty($_POST["p6"])){ $p6 = $_POST["p6"]; }
if(! empty($_POST["p7"])){ $p7 = $_POST["p7"]; }
if(! empty($_POST["p8"])){ $p8 = $_POST["p8"]; }
if(! empty($_POST["p9"])){ $p9 = $_POST["p9"]; }
if(! empty($_POST["p10"])){ $p10 = $_POST["p10"]; }

//print "[" . $querydef["USER"] . "]<br>";
//print "[" . $querydef["PASSWORD"] . "]<br>";
//print "[" . $querydef["DATABASE"] . "]<br>";
//print "[" . $querydef["QUERY"] . "]<br>";

// 出力ファイルのパスを作成します。
$aaa = $querydef["OUTPUT-FILENAME-FORMAT"];
if(strstr($aaa, "%r")){
  srand(time());
  $aaa = str_replace("%r", (string) rand(0, 99999), $aaa);
}
if(strstr($aaa, "%Y") || strstr($aaa, "%H")){
  $aaa = strftime($aaa);
}

$outputFileName = $OUTPUTFILEDIR . "/" . $aaa;
$outputURL = "./${workdirrelpath}/${aaa}";

// データベースに接続します。
$con = OCILogon($querydef["USER"], $querydef["PASSWORD"], $querydef["DATABASE"]);

$stmt = OCIParse($con, $querydef["QUERY"]);
if(! empty($p1)){ OCIBindByName($stmt, ":p1", &$p1, 100); }
if(! empty($p2)){ OCIBindByName($stmt, ":p2", &$p2, 100); }
if(! empty($p3)){ OCIBindByName($stmt, ":p3", &$p3, 100); }
if(! empty($p4)){ OCIBindByName($stmt, ":p4", &$p4, 100); }
if(! empty($p5)){ OCIBindByName($stmt, ":p5", &$p5, 100); }
if(! empty($p6)){ OCIBindByName($stmt, ":p6", &$p6, 100); }
if(! empty($p7)){ OCIBindByName($stmt, ":p7", &$p7, 100); }
if(! empty($p8)){ OCIBindByName($stmt, ":p8", &$p8, 100); }
if(! empty($p9)){ OCIBindByName($stmt, ":p9", &$p9, 100); }
if(! empty($p10)){ OCIBindByName($stmt, ":p10", &$p10, 100); }
$r = OCIExecute($stmt, OCI_DEFAULT);
$ncols = OCINumCols($stmt);

// 出力ファイルをオープンし、結果集合を書き込みます。
$fout = fopen($outputFileName, "w");
if(! $fout){
  print "ERROR CODE=64<br>\n"; exit;
}

// 見出し行を出力
if(! empty($querydef["HEADER"])){
  fwrite($fout, str_replace("|", "\t", $querydef["HEADER"]) . "\n");
}

for($y=0; OCIFetchInto($stmt, &$arr); $y++){
  $rowdata = "";
  for($i=0; $i<$ncols; $i++){
    if($i>0){ $rowdata .= "\t"; }
    $rowdata .= $arr[$i];
  }
  fwrite($fout, $rowdata . "\n");
}

// クローズ・ログオフ処理
fclose($fout);
OCIFreeStatement($stmt);
OCILogoff($con);
?>
データの出力に成功しました。<br>
<a href="<?= $outputURL ?>">こちら</a>からダウンロードできます。

</body>
</html>

 セットアップ手順はこんな感じです。

  1. まず、このスクリプトをApacheの文書ツリーのどこかのディレクトリに置きます。
  2. その下に、出力データファイルを格納する、workという名前のサブディレクトリを作ります。 この名前は、スクリプトにべた書きで指定しているので、 そこを変えれば変えられます。
  3. スクリプトと同じディレクトリに、一意の主ファイル名を持つXMLファイルを作ります。 ここでは例えばexample.xmlという名前で、 次のようなファイルを置いたとします。

    <?xml version="1.0" encoding="Shift_JIS"?>
    <querydef>
    <user>webuser</user>
    <password>webpass</password>
    <database>udb</database>
    <query>
    SELECT SHITEN_CODE, SHITEN_NAME, TO_CHAR(CDATE, 'YYYY/MM/DD')
      FROM SHITEN
    WHERE AREA_CODE = :p1
    ORDER BY SHITEN_CODE
    </query>
    <header>
    支店コード|支店名|登録日
    </header>
    <output-filename-format>download-%Y%m%d-%r.txt
    </output-filename-format>
    </querydef>
    

  4. 任意のWebフォームを持つHTML文書から、 このスクリプト(websql.php)に飛びます(WebフォームのACTION=の値をこのスクリプトのURLにします)。 その際、POST変数で上記の接続情報を書いたXMLファイルの主ファイル名 (この場合は「example」)を渡します。
  5. そうすると、workサブディレクトリの中に、XMLのoutput-filename-format タグで指定したフォーマットで、データファイルが作られます。
※なお、XML文書の見出し(header)に日本語を使い、 Oracleのデータにも日本語が含まれる場合、 PHPが見出しを出力するコードと、Oracleの文字コードを統一しておく必要があります。

Open Source Web Architecture Top

(first uploaded 2003/01/18 last updated (not ever), URANO398)

楽天モバイル[UNLIMITが今なら1円] ECナビでポインと Yahoo 楽天 LINEがデータ消費ゼロで月額500円〜!


無料ホームページ 無料のクレジットカード 海外格安航空券 解約手数料0円【あしたでんき】 海外旅行保険が無料! 海外ホテル