国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 數據庫 > Oracle > 正文

Oracle PHP 故障診斷常見問題以及解答

2024-08-29 13:42:00
字體:
來源:轉載
供稿:網友
主題
  Oracle 沒有安裝或沒有找到
  在啟動 Apache 之前,在 shell 或環境中設置所有的 Oracle 環境變量
  與數據庫連接
  回顯 SQL 語句,以檢查它們是否得到正確設計
  始終測試來自數據庫函數調用的返回代碼
  插入包含引號的字符串
  在 php 中使用 Oracle 賦值變量
  上載 LOBS
  PHP 中的數組獲取
  PEAR DB 中的 Oracle 錯誤消息
  OCI 線程安全
  使用 AS SYSDBA 或 AS SYSOPER 進行連接
  PHP 中的 NCHAR 和 NCLOB 支持
  
  --------------------------------------------------------------------------------
  
  Oracle 沒有安裝或沒有找到
  
  假如在 PHP 中啟用了 Oracle 支持,但未能找到 Oracle 客戶端資料庫,那么當您試圖啟動 Apache 時,將得到一個錯誤。例如,在 Windows 上,假如 php.ini 有 "extension=php_oci8.dll",但未能找到 Oracle 主頁,則一條警告 "The dynamic link library OCI.dll could not be found in the specified path ...." 將被顯示出來。
  
  在啟動 Apache 之前,確保 Oracle 環境變量被正確設置(參見下一主題)。此外,請參考由 Rob Clevenger 提供的 OTN 文章 在 windows 2000/XP 上安裝 Oracle、PHP 和 Apache。
  
  linux 用戶可能看到一個關于不能加載 libclntsh.so 的 Apache 錯誤,但更可能在之前編譯 PHP 時注重到這個問題。編譯器將以一個錯誤 'Cannot find file "ocidfn.h"' 或 'Cannot find file "oci.h"' 而失敗。
  
  確保 Oracle 目錄對編譯 PHP 的 OS 用戶是可讀的。假如您安裝了 Oracle,但丟失了 Oracle 頭文件,請執行一次 Oracle 的 "Client" 安裝。"Client" 安裝指的是 Oracle9i Database Release 安裝器中那個名稱的選項。(給出的其它三個選項是 Database、Management and Integration、和 Cluster Management)。此外,還請參考 OTN 文章在 Linux 上安裝 Oracle、PHP 和 Apache。
  
  --------------------------------------------------------------------------------
  
  在啟動 Apache 之前,在 shell 或環境中設置所有的 Oracle 環境變量。
  
  在 Apache 啟動之前設置所有的 Oracle 環境變量是使 PHP 能夠與 Oracle 通信的一種安全的方法。在 PHP 腳本或 httpd.conf 文件中設置變量通常不起作用。由于通常對環境的混淆,存在許多郵件列表和論壇帖子。在 Windows 和 Linux 上的行為也不同。
  
  OTN 文章 在 Linux 上安裝 Oracle、PHP 和 Apache 給出了一個名為 "start_apache" 的、用來設置環境和啟動 Apache 的例子:
  
     #!/bin/sh
     ORACLE_HOME=/u01/app/oracle/PRodUCt/9.2
  
     ORACLE_SID=orcl
     export ORACLE_HOME ORACLE_SID
     echo "Oracle Home: $ORACLE_HOME"
     echo "Oracle SID: $ORACLE_SID"
     echo Starting Apache
     ./apachectl start
  
  我做了一些測試來查看該環境對 PHP 調用有什么影響:
  
     $mycon = OCILogon("myusername", "mypassWord", "MYDB");
  
  我用了 RedHat Linux AS 2.1、Apache 1.3 和 PHP 4.3.3。
  
  在 "apachectl start" 之前沒有設置 ORACLE_HOME 并且在 PHP 腳本中沒有 "putenv('ORACLE_HOME=/usr/oracle/MYDB')" 的情況下,我得到:
  
  Warning:ocilogon():_oci_open_server:
  Error while trying to retrieve text for error ORA-12154
  
  這顯示連接失敗,未能找到消息文件(這些文件位于 Oracle 主目錄下)。
  
  在 PHP 腳本中有 "putenv('ORACLE_HOME=/usr/oracle/MYDB')",但沒有設置 ORACLE_HOME 的情況下,我得到:
  
  Warning:ocilogon():_oci_open_server:
  ORA-12154:TNS:could not resolve service name
  
  連接仍然沒有成功,但在錯誤出現之后能夠從消息文件中讀出消息正文。
  
  在 "apachectl start" 之前設置了 ORACLE_HOME 但沒有 "putenv()" 的情況下,連接成功了。這是推薦的配置。
  
  在 "apachectl start" 之前正確設置 ORACLE_HOME 同時 "putenv()" 使用一個無效 ORACLE_HOME 目錄的情況下,連接成功。我也在 Windows 上試驗了這種情況。這次,連接失敗了,出現和我上面的第一次測試同樣的消息。
  
  當我用一條 Apache httpd.conf 指令 "setenv ORACLE_HOME /usr/oracle/MYDB" 來替換 PHP putenv() 調用時,得到了一組類似的結果。
  
  一些變量可以在 PHP 腳本中設置。在啟動 Apache 之前正確設置 ORACLE_HOME 之后,以下操作改變了我的默認連接,并連接到 MYDB:
  
  putenv("TWO_TASK=MYDB");
  $mycon = OCILogon("myusername", "mypassword");
  
  環境變量 TNS_ADMIN、NLS_DATE_FORMAT(可能還有其它變量)也可以用這種方式來設置。
  
  --------------------------------------------------------------------------------
  
  與數據庫連接
  
  用戶選擇的網絡服務名稱經常用來識別要與哪個數據庫連接。它被默認從環境變量 ORACLE_SID 中讀出,或者它可以在連接調用中顯式地給出。網絡服務名稱 MYDB 可以用在 Oracle 的命令行 SQL*Plus 實用程序中,如:
  
  sqlplus myusername/mypassword@MYDB
  
  
  或用在 PHP 中,如:
  
  $mycon = OCILogon("myusername", "mypassword", "MYDB");
  
  網絡服務名稱通常通過 tnsnames.ora 文件中的一個項目映射到一個實際的數據庫上:
  
     MYDB =
      (DESCRipTION =
       (ADDRESS_LIST =
        (ADDRESS = (PROTOCOL = TCP)(HOST = mymachine.mydomain)(PORT = 1535))
       )
       (CONNECT_DATA =
        (SERVER = DEDICATED)
        (SERVICE_NAME = MYDB.mydomain)
       )
      )
  
  $ORACLE_HOME/network/admin/tnsnames.ora 文件被默認使用。在一些操作系統上,假如默認文件不存在,則將檢查其它的位置。
  
  假如在 tnsnames.ora 中找不到被用在 OCILogon() 中的網絡服務名稱,或者 PHP 根本沒找到 tnsnames.ora,那么您在登錄時可能得到一個錯誤:
  
  Warning:ocilogon():_oci_open_server:ORA-12154:TNS:could not resolve service name
  
  在啟動 Apache web server 之前,檢查環境變量 ORACLE_HOME 是否正確設置(參見之前的主題)。
  
  假如您的 tnsnames.ora 在一個非默認的位置,您可以將環境變量 TNS_ADMIN 設置為包含它的目錄。例如,假如您在使用 /tmp/tnsnames.ora,將這些行添加到 start_apache 中(同樣,參見之前的主題):
  
  TNS_ADMIN=/tmp
  export TNS_ADMIN
  
  另一種解決辦法是在 OCILogon() 調用中使用完整的連接字符串:
  
     $db = "(DESCRIPTION=(ADDRESS_LIST=(ADDRESS=(PROTOCOL=TCP)
            (HOST = mymachine.mydomain)(PORT=1535)))
            (CONNECT_DATA=(SERVER=DEDICATED)
            (SERVICE_NAME=MYDB.mydomain)))";
  
     $mycon = OCILogon("myusername", "mypassword", $db);
     ...
  
  假如 $ORACLE_HOME/network/admin/sqlnet.ora 與 tnsnames.ora 不同步且一個域名被隱式地添加到了別名中,那么錯誤 ORA- 12154 也可能發生。OCILogon() 調用中的不合格網絡服務名稱將添加 sqlnet.ora 的 NAMES.DEFAULT_DOMAIN 值。例如,假如 sqlnet.ora 有:
  
  NAMES.DEFAULT_DOMAIN = au.oracle.com
  
  那么 'OCILogon("myusername", "mypassword", "mydb")' 將使 Oracle 在 tnsnames.ora 中尋找別名 "MYDB.AU.ORACLE.COM = ..."。一種快速的解決辦法是將 tnsnames.ora 項目改變為:
  
      MYDB.AU.ORACLE.COM =
       (DESCRIPTION =
        (ADDRESS_LIST =
         (ADDRESS = (PROTOCOL = TCP)(HOST = mymachine.mydomain)(PORT = 1535))
        )
        (CONNECT_DATA =
         (SERVER = DEDICATED)
         (SERVICE_NAME = MYDB.mydomain)
        )
       )
  
  --------------------------------------------------------------------------------
  
  回顯 SQL 語句,檢查它們是否得到正確設計
  
  令人意外的是,沒有得到結果或者得到錯誤的結果經常歸因于執行了錯誤的語句。在開發期間,從 PHP 回顯每一條完整的 SQL 語句,檢查它是否得到正確設計、所有變量是否得到了正確擴展。引用錯誤或者對字符串中 PHP 的變量語法的錯誤理解可能導致不正確的語句被執行。
  
  在執行它們之前測試 SQL*Plus 中的 SQL 語句也有助于確認正確性。
  
  當語句被輸入到諸如 SQL*Plus 之類的工具中時,通常用一個分號來告訴工具這個語句完成了,現在可以被執行。不過,分號不被認為是語句的一部分,并且不會被發送到數據庫中。在 PHP 中,不要向 SQL 語句中添加分號,否則將出現一個 Oracle 錯誤。這個例子是一次有效的查詢:
  
  
  $sql = "SELECT * FROM EMP_DETAILS_VIEW";
  
  Oracle 內置的腳本語言 PL/SQL 具有與 SQL 不同的語法,在句尾需要一個分號:
  
  $plsql = "BEGIN DBMS_OUTPUT.PUT_LINE('hi'); END;";
  
  --------------------------------------------------------------------------------
  
  始終測試來自數據庫函數調用的返回代碼
  
  測試來自 OCI 函數的所有返回值,防止隱藏的問題和誤導性的結果。
  
  為了進行基本的測試,將 php.ini 的 error_reporting 指令設置為 E_ALL。 此外,設定 display_errors,或配置錯誤日志文件(記得檢查它!)。這將在 Oracle 錯誤出現時顯示它們,除非您已經顯式地為 Oracle 函數調用添加了前綴 "@"。
  
  --------------------------------------------------------------------------------
  
  插入包含引號的字符串
  
  插入包含單引號的字符串可以用幾種方式來處理:
  
  使用賦值變量。這還為 "SQL Injection" 安全性問題提供了保護:
  
      $name = "O'Reilly";
      $stmt = 'INSERT INTO CUSTOMERS (NAME) VALUES (:nm)';
      $stid = OCIParse($mycon, $stmt);
      OCIBindByName($stid, ':nm', $name, -1);
      OCIExecute($stid);
  
  使所有的單引號變為雙引號:
  
      $name = "O'Reilly";
      $name = str_replace("'", "''", $name);
      $stmt = "INSERT INTO CUSTOMERS (NAME) VALUES ('".$name."')";
  
  打開 php.ini 中的 magic_quotes_sybase,然后使用 addslashes():
  
  $name = addSlashes("O'Reilly");
  $stmt = "INSERT INTO CUSTOMERS (NAME) VALUES ('".$name."')";
  
  由于可移植性問題,不推薦這么做。
  
  --------------------------------------------------------------------------------
  
  
  在 PHP 中使用 Oracle 賦值變量
  
  綁定問題經常由于需要在調用 OCIExecute() 時(而不只是在 OCIBindByName() 被執行時)訪問數值而引起。
  
  假如 OCIBindByName() 在一個包裝函數或方法內部被調用,而傳遞給 OCIBindByName() 的 PHP 變量對該包裝函數而言是本地的,那么就可能存在問題。當 OCIExecute() 稍后被調用時,變量需要在有效范圍中。否則可能出現一個諸如 "OCIStmtExecute:ORA-01460:unimplemented or unreasonable conversion requested" 之類的 Oracle 錯誤;或者,它可能看似沒有為 "OUT" 變量設定值,令人迷惑。
  
  下面的示例是上述情況的一個變樣。變量 "$val" 對 "foreach" 命令而言是本地的。代碼沒有返回記錄:
  
     $dn, ':loc' => $lc);
  
     $conn = OCILogon('myusername', 'mypassword', 'mydb');
     $stmt = OCIParse($conn, $qs);
  
     foreach ($ba as $key => $val)
     {
      OCIBindByName($stmt, $key, $val, -1);
     }
  
     OCIExecute($stmt);
  
     while ($succ = OCIFetchInto($stmt, $o)) {
      foreach ($o as $mv) {
       echo $mv." ";
      }
      echo "/n";
     }
  
     ?>
  
  修改 OCIBindByName() 調用可以解決這個問題:
  
     ...
     foreach ($ba as $key => $val)
     {
      OCIBindByName($stmt, $key, $ba[$key], -1);
     }
     ...
  
  --------------------------------------------------------------------------------
  
  上載 LOBS
  
  在 OCINewDescriptor() 人工輸入中給出了上載 BLOB 的一些示例代碼。下面是加載 CLOB 的一個最新示例。
  
  小心 Html 腳本中的大小限制:
  
  或者 httpd.conf 中 LimitRequestBody 指令中的大小限制(參考 PHP Bug 22138):
  
  一個上載到 CLOB 中的示例是:
  
    
     // using PHP's Oracle 8 API.
     //
     // Based on http://www.php.net/manual/en/function.ocinewdescriptor.php
     // modified to work on CLOBs and use register_globals = Off.
     //
     // Before running this script, execute these statements in SQL*Plus:
     //  drop table mycloBTab;
     //  create table myclobtab (c1 number, c2 clob);
     //
     // Tested with PHP 4.3.3 against Oracle 9.2
     //
  
     if (!isset($_FILES['lob_upload'])) {
      ?>
  
    
     Upload file:  
  
      $conn = OCILogon('myusername', 'mypassword', 'mydb');
  
      // Delete any existing CLOB so the query at the bottom
      // displays the new data
  
      $query = 'DELETE FROM MYCLOBTAB';
      $stmt = OCIParse ($conn, $query);
      OCIExecute($stmt, OCI_COMMIT_ON_SUCCESS);
      OCIFreeStatement($stmt);
  
      // Insert the CLOB from PHP's tempory upload area
  
      $lob = OCINewDescriptor($conn, OCI_D_LOB);
      $stmt = OCIParse($conn, 'INSERT INTO MYCLOBTAB (C1, C2) VALUES('.
              $myid . ', EMPTY_CLOB()) RETURNING C2 INTO :C2');
      OCIBindByName($stmt, ':C2', $lob, -1, OCI_B_CLOB);
      OCIExecute($stmt, OCI_DEFAULT);
  
      // The function $lob->savefile(...) reads from the uploaded file.
      // If the data was already in a PHP variable $myv, the
      // $lob->save($myv) function could be used instead.
      if ($lob->savefile($_FILES['lob_upload']['tmp_name'])) {
       OCICommit($conn);
       echo "Clob successfully uploaded/n";
      }
      else {
       echo "Could not upload Clob/n";
      }
      $lob->free();
      OCIFreeStatement($stmt);
  
      // Now query the uploaded CLOB and display it
  
      $query = 'SELECT C2 FROM MYCLOBTAB WHERE C1 = '.$myid;
  
      $stmt = OCIParse ($conn, $query);
      OCIExecute($stmt, OCI_DEFAULT);
      OCIFetchInto($stmt, $arr, OCI_ASSOC);
      $result = $arr['C2']->load();
  
      echo '';
      echo $result;
      echo '';
  
      OCIFreeStatement($stmt);
  
      OCILogoff($conn);
     }
     ?>
  
  
  --------------------------------------------------------------------------------
  
  PHP 中的數組獲取
  
  在 PHP 中沒有數組獲取功能,但用 OCISetPrefetch() 來預先獲取行數是類似的,并且可以顯著地提高性能。設置預取行數而不是數組大小的好處是 Oracle 將為您執行高速緩存。您的數據結構一次只需處理一行,而且您的代碼通常能夠更簡單。
  
  設置預取行數為 100 的示例如:
  
     /n";
     }
  
     OCILogoff($conn);
  
     ?>
  
  --------------------------------------------------------------------------------
  
  PEAR DB 中的 Oracle 錯誤消息
  
  PEAR DB 接口是一個數據庫抽象層,它對不同品牌的數據庫使用同樣的語法。標準的 PEAR DB 錯誤函數 $db->getMessage() 返回一條簡單的 PEAR 錯誤說明。例如,假如由于任何原因連接失敗,消息始終為:
  
     DB Error: connect failed
  
  通過使用以下方法,您可以獲得準確的 Oracle 錯誤號和消息:
  
     $db->getDebugInfo()
  
  
  它包括 Oracle 錯誤和完整的語句,如:
  
  [nativecode=ORA-01017:invalid username/password; logon denied ]
  ** oci8://myusername:wrongpassword@mydb
  
  利用一個包裝函數,可以從這個字符串中提取出 Oracle 消息正文。例如:
  
     require_once('DB.php');
  
     $db = DB::connect("oci8://myusername:mypassword@mydb");
     if (DB::iserror($db)) {
      PrintPEARDBError($db);
      die();
     }
  
     .
     .
     .
  
     // Display PEAR DB error
     function PrintPEARDBError($e)
     {
      if (is_object($e)) {
       $s = preg_match('/.*/[nativecode=(.*)/', $e->getDebugInfo(), $r);
       $etxt = $s ? $r[1] : $e->getDebugInfo();
      }
      else {
       $etxt = "Unknown Error";
      }
      echo "Error:/n  ".htmlspecialchars($etxt)."/n";
     }
  
  
  來自 PrintPEARDBError() 的輸出是:
  
  ERROR:
     ORA-01017: invalid username/password; logon denied
  
  --------------------------------------------------------------------------------
  
  OCI 線程安全
  
  PHP 庫在一個 bug — 這個 bug 在 4.3.4 版(在編寫時這是最新的版本)發布之后得到了修復 — 中具有 OCI 線程安全性。在實踐中,似乎只有加載的服務器碰到了問題,這些問題有隨機的行為(包括崩潰)。補丁在最新的快照中提供。參見 PHP bug 26558 和 PHP Bug 26393
  
  --------------------------------------------------------------------------------
  
  使用 AS SYSDBA 或 AS SYSOPER 進行連接
  
  在 PHP 中連接 AS SYSDBA 或 AS SYSOPER 是不可能的。
  
  PHP 的 oci8.c 中對 Oracle 的 OCIsessionBegin() 函數的調用始終傳遞 OCI_DEFAULT。為了答應授權的連接,這將需要更改為 OCI_SYSDBA 或 OCI_SYSOPER。但這個示例解決方案打開了一個潛在的安全漏洞,參見 Re:關于 php ocilogon() oracle OCI FUNCTION 的建議
  
  


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
主站蜘蛛池模板: 锡林浩特市| 古蔺县| 吉首市| 和田市| 东乡县| 会昌县| 娱乐| 天全县| 黎川县| 微山县| 邢台市| 嘉义县| 阳原县| 石泉县| 涪陵区| 武陟县| 邹平县| 鄱阳县| 临夏市| 洛川县| 博爱县| 鲁甸县| 盐边县| 义乌市| 拉萨市| 达孜县| 西贡区| 鸡东县| 通道| 河东区| 南靖县| 中牟县| 茶陵县| 普定县| 阿合奇县| 西平县| 康保县| 辉南县| 佛山市| 彝良县| 南岸区|