<?php

class dbUtil {
  private $logger;
  private $dbh;
  private $myseq;
  private $maxcnt;

  function __construct($seq="") {   //複数DB対応
    global $settingUtil;

    $this->logger = new logger(basename(__FILE__));
    $maxcnt = 10000;

    if ($seq == "") { //引数無しなら起動時に取得した番号 dbxx.jsonとする
      $seq = $GLOBALS['SYSTEM_NO'];
    }
$this->logger->info("seq:".$seq);

    $host = $settingUtil->getDbParam("host",$seq);
    $port = $settingUtil->getDbParam("port",$seq);
    $sid  = $settingUtil->getDbParam("sid" ,$seq);
    $service  = $settingUtil->getDbParam("service" ,$seq);
    $tnsmode  = $settingUtil->getDbParam("tnsmode" ,$seq);
$this->logger->info("tnsmode:".$tnsmode);

    if ($tnsmode == "1") {  //Oracle19
      $dbtns = " (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = ".$host.")(PORT = ".$port."))) (CONNECT_DATA =(SERVICE_NAME = " . $service . ") ) )";
    } else {  //Oracle12c以下
      $dbtns = " (DESCRIPTION = (ADDRESS_LIST = (ADDRESS = (PROTOCOL = TCP)(HOST = ".$host.")(PORT = ".$port."))) (CONNECT_DATA = (SID = ".$sid.")))";
    }
$this->logger->info($dbtns);
    $this->db_username = $settingUtil->getDbParam("username", $seq);
    $this->db_password = $settingUtil->getDbParam("password", $seq);
    $this->db = "oci:dbname=" . $dbtns . ";charset=" . $settingUtil->getDbParam("charset",$seq);

    try {
      $this->dbh = new PDO($this->db, $this->db_username, $this->db_password);
      $this->dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
      $this->dbh->beginTransaction();
//$this->logger->error("Start_Transaction");
    } catch (PDOException $e) {
      $this->logger->error($e);
      $this->logger->error($this->dbh);
      $this->logger->error("host", $host . "+" . $port);
      $this->dbh->rollBack();
      $this->logger->error("E001", "エラー!: " . $e->getMessage(), __FILE__, __LINE__);
      $this->logger->error("E002". "エラー!: " , $e->getMessage(), __FILE__, __LINE__);
      die();
    }
  }

  public function commit() {
    if( $this->dbh != null ) {
      $this->dbh->commit();
    }
  }
  public function rollback() {
    if( $this->dbh != null ) {
      $this->dbh->rollBack();
    }
  }
  public function getNoDataMsg() {
    return "対象のデータがありません";
  }

  /**
   * where : [":".filed => value,,,]の形の配列 フィールドの前にコロンを付ける
   *
   */
  public function select($sql, $where=null, $order=null, $maxcnt=null) {
    // SELECT 前に件数取得
    $cnt = $this->getSelectCount($sql, $where);
    $this->logger->sql("count", $cnt);
    $selectCnt = $cnt[0]["cnt"];
    $this->logger->error("E0100", $selectCnt, __FILE__, __LINE__);;
    if( $selectCnt == 0 ) {
      return null;
    }

    if($maxcnt == null ) {
      if( intval( $selectCnt) > 10000) {
        throw new userException("E0100", "結果が10,000件を超えてます。条件を絞って下さい。", $sql, __FILE__, __LINE__);
        return null;
      }
    } else {
      if( intval( $selectCnt ) > intval( $maxcnt ) ) {
        throw new userException("E0100", "結果が".$maxcnt."件を超えてます。条件を絞って下さい。", $sql, __FILE__, __LINE__);
        return null;
      }
    }

    if($order != null){
      $sql = $sql . " and rownum < 10000" . " order by " . $order;
    }
    $result = $this->execute($sql, $where, false);
    return $result;
  }
  public function SELECTNOCOUNT($sql, $where=null, $order=null) {
    if($order != null){
      $sql = $sql . " order by " . $order;
    }
    return $this->execute($sql, $where, false);
  }

  public function insert($sql, $params) {
    return $this->execute($sql, $params, true);
  }
  public function update($sql, $params) {
    return $this->execute($sql, $params, true);
  }
  public function delete($sql, $params) {
    return $this->execute($sql, $params, true);
  }
  public function nextVal($seq) {
    $sql = "select " . $seq . ".nextval from dual";
    $result = $this->execute( $sql, [], false )[0]["nextval"];
    return $result;
  }
  public function insertCsv($sql, $params) { //csv取込時は文字コード変換不要
    $result = array();
    $sth = null;
    try {
//      $this->logger->sql("motosql",     $sql);
      $sql = preg_replace('/(\n|\r|\r\n)/', ' ', $sql );
      // sqlファイルはUTF-8のため
      $sql = mb_convert_encoding($sql,"SJIS-win","utf8");

//      $this->logger->sql("sql",     $sql);
//      $this->logger->sql("params",  $params);

      foreach((array)$params as $key => $val) {
        $whereParams[":".$key] = $val;
      }

      $sth = $this->dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
      //$sth = $this->dbh->prepare($sql);
      if($sth == FALSE) {
        throw new userException("E0003", "SQL構成失敗", $sql, __FILE__, __LINE__);
      }
      $isOK = $sth->execute($whereParams);

      if($isOK) {
        // 結果行を返却する
        $result = $sth->rowCount();
      } else {
        $errorInfo = $this->dbh->errorInfo();
        $this->logger->Error("E0004", $errorInfo);
        $code = "C" . $errorInfo[1];
        $msg = mb_convert_encoding($errorInfo[2], "utf8", "sjis-win");
        throw new userException("E0004", "SQL実行失敗[" . $code . "]", $sql, __FILE__, __LINE__);
        return null;
      }
      $sth = null;
    } catch (PDOException $e) {
      $sth = null;
      $this->logger->Error("E0005", mb_convert_encoding($e->getMessage(), "utf8", "sjis-win"));
      //throw new userException("E0005", $e->getCode(), $sql, __FILE__, __LINE__);
      throw new userException("E0005", $e->getCode(), $e, __FILE__, __LINE__);
      die();
    }
    $this->logger->sqlRet("RESULT001", $result);
    return $result;
  }

  /**
   * プロシージャを実行する。
   *
   */
  public function call($sql, $params) {
    $result = array();
    try {
      $this->logger->sql("sql", $sql);
      $this->logger->sql("params", $params);

      $sth = $this->dbh->prepare($sql);

      foreach($params as $key => $val) {
        $this->logger->sql("params_key", $key);
        $this->logger->sql("params_val", $val);

        $bindp = ":".$key;

        if(array_key_exists("out", $val)) {
          $ret[$key]="@";
          $sth->bindParam($bindp, $ret[$key], PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 4000);
        }
        //if($val["in"] != null) {
        if(array_key_exists("in", $val)){
          $ret[$key]=mb_convert_encoding($val["in"], "SJIS-win", "utf8");
          $sth->bindParam($bindp, $ret[$key], PDO::PARAM_STR|PDO::PARAM_INPUT_OUTPUT, 4000);
        }
      }

      $isOK = $sth->execute();
      $this->logger->sql("result", $ret);

      // SJIS->UTF-8
      foreach($ret as $key => $val) {
        $newVal = mb_convert_encoding($val, "utf8", "sjis-win");
        $r[$key] = $newVal;
      }

    } catch (PDOException $e) {
      $sth = null;
      $this->logger->Error("E0005", $e->getMessage());
      throw new userException("E0005", $e->getCode(), $sql, __FILE__, __LINE__);
      die();
    } finally {
      $sts = null;
    }
    $this->logger->sqlRet("RESULT001", $r);

    return $r;
  }


  private function execute($sql, $params, $isUpdate) {
    $result = array();
    $sth = null;
    try {
      $this->logger->sql("motosql",     $sql);
      $sql = preg_replace('/(\n|\r|\r\n)/', ' ', $sql );
      // sqlファイルはUTF-8のため
      $sql = mb_convert_encoding($sql,"SJIS-win","utf8");

      $this->logger->sql("sql",     $sql);
      $this->logger->sql("params",  $params);

      foreach((array)$params as $key => $val) {
        $whereParams[":".$key] = mb_convert_encoding($val,"sjis-win","utf8");
      }

      $sth = $this->dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
      //$sth = $this->dbh->prepare($sql);
      if($sth == FALSE) {
        throw new userException("E0003", "SQL構成失敗", $sql, __FILE__, __LINE__);
      }
      $isOK = $sth->execute($whereParams);

      if($isOK) {
        if(!$isUpdate) {
          $ret = $sth->fetchAll(PDO::FETCH_ASSOC);
          $this->logger->sqlRet("RESULT000", $ret);
          foreach($ret as $d1) {
            $d = array_change_key_case($d1);
            mb_convert_variables("utf8", "SJIS-win", $d);
            array_push($result, $d);
          }
        } else {
          // 結果行を返却する
          $result = $sth->rowCount();
        }
      } else {
        $errorInfo = $this->dbh->errorInfo();
        $this->logger->Error("E0004", $errorInfo);
        $code = "C" . $errorInfo[1];
        $msg = mb_convert_encoding($errorInfo[2], "utf8", "sjis-win");
        throw new userException("E0004", "SQL実行失敗[" . $code . "]", $sql, __FILE__, __LINE__);
        return null;
      }
      $sth = null;
    } catch (PDOException $e) {
      $sth = null;
      $this->logger->Error("E0005", mb_convert_encoding($e->getMessage(), "utf8", "sjis-win"));
      //throw new userException("E0005", $e->getCode(), $sql, __FILE__, __LINE__);
      throw new userException("E0005", $e->getCode(), $e, __FILE__, __LINE__);
      die();
    }
    $this->logger->sqlRet("RESULT001", $result);
    return $result;
  }

  private function getSelectCount($sql, $where) {
    $s = "select count(*) as CNT from (" . $sql . " )";
    $result = $this->execute($s, $where, false);
    $this->logger->sqlRet("===RESULT===", $result[0]);

    return $result;
  }

  /**
   * CSV出力用、CSV出力だけなのでメモリ使わないようにする。
   *
   */
  public function createCsvEx2($export_csv_title,$sql, $where=null, $order=null,$delimiter = ",", $enclosure = '"', $endmarkflg = "0") {
    if($order != null){
      $sql = $sql . " order by " . $order;
    }
    $rowcount = 0;
    $result = array();
    $sth = null;

    // ファイル名
    global $serverUtil;
    global $stringUtil;

    $topDir = $serverUtil->getProjectDir();
    $file_path = $topDir . "/dl/" . uniqid(). ".csv";

    //改行コード
    if ($endmarkflg == '0') { //default
      $endmark = "\r\n";
    } else if ($endmarkflg == '1') {
      $endmark = "\r";
    } else if ($endmarkflg == '2') {
      $endmark = "\n";
    } else if ($endmarkflg == '3') {
      $endmark = "";
    }

    if( touch($file_path) ){
      // オブジェクト生成
      $file = new SplFileObject( $file_path, "w" );

      // タイトル行のエンコードをSJIS-winに変換（一部環境依存文字に対応用）
      if ($export_csv_title != null) {  //タイトルがある場合のみ
        $buff = "";
        $i = 0;
        foreach( $export_csv_title as $key => $val ){
          if ($i > 0) {
            $buff .= $delimiter;
          }
          $buff .= $enclosure.mb_convert_encoding($val, 'SJIS-win', 'UTF-8').$enclosure;
          $i++;
        }
        $buff .= $endmark;

        // エンコードしたタイトル行を配列ごとCSVデータ化
        $file->fwrite($buff);
      }
        try {
          $this->logger->sql("motosql",     $sql);
          $sql = preg_replace('/(\n|\r|\r\n)/', ' ', $sql );
          // sqlファイルはUTF-8のため
          $sql = mb_convert_encoding($sql,"SJIS-win","utf8");

          $sth = $this->dbh->prepare($sql, array(PDO::ATTR_CURSOR => PDO::CURSOR_FWDONLY));
          if($sth == FALSE) {
            throw new userException("E0003", "SQL構成失敗", $sql, __FILE__, __LINE__);
          }

          if (is_array($where)) {
            foreach($where as $key => $val) {
              $whereParams[":".$key] = mb_convert_encoding($val,"sjis-win","utf8");
            }
            $isOK = $sth->execute($whereParams);
          } else {
            $isOK = $sth->execute();
          }

          if($isOK) {
            if(!$isUpdate) {
              while ($ret1 = $sth->fetch(PDO::FETCH_ASSOC)) {
                $export_arr = [];
                $i = 0;
                $buff = "";
                while(list($key, $val) = each($ret1)) {
                  // エンコードしない。
                  if ($i > 0) {
                    $buff .= $delimiter;
                  }
                  $buff .= $enclosure.$val.$enclosure;
                  $i++;
                }
                $buff .= $endmark;
                $file->fwrite($buff);
                $rowcount++;
              }
            }
          } else {
            $errorInfo = $this->dbh->errorInfo();
            $this->logger->Error("E0004", $errorInfo);
            $code = "C" . $errorInfo[1];
            $msg = mb_convert_encoding($errorInfo[2], "utf8", "sjis-win");
            throw new userException("E0004", "SQL実行失敗[" . $code . "]", $sql, __FILE__, __LINE__);
            return null;
          }
          $sth = null;
        } catch (PDOException $e) {
          $sth = null;
          $this->logger->Error("E0005", mb_convert_encoding($e->getMessage(), "utf8", "sjis-win"));
          throw new userException("E0005", $e->getCode(), $sql, __FILE__, __LINE__);
          die();
          return null;
        } catch (Exception $e) {
          $sth = null;
          $this->logger->Error("E0005", mb_convert_encoding($e->getMessage(), "utf8", "sjis-win"));
          throw new userException("E0005", $e->getCode(), $sql, __FILE__, __LINE__);
          die();
          return null;
        }
        $this->logger->sqlRet("RESULT001", $result);

      $file->fflush();

    }

    return $file_path;


  }

}

?>
