oracle clog读取 php,让ThinkPHP3.2.3 支持对Oracle LOB数据的操作

让ThinkPHP3.2.3 支持对Oracle LOB数据的操作

1. 问题由来

直接用PHP存取oracle的clob也是会自动截断。当需要插入的数据很大,会直接报错。ThinkPHP 3.2.3 封装的CURD也不能解决这个问题。

这个时候就需要使用PHP OCI8的拓展函数库。

2. 配置PHP:OCI8

首先,原理是利用PHP OCI8的拓展函数库。所以,必须先把OCI8,和php_oci8和php_oci8_11 功能开启。

可以wampserver上直接进行设置。如下图:

11da9bab1084d77ff2ce6add7022bc36.png

设置成功后,可以通过phpinfo() 查看,显示enabled即开启成功,如下图。

1e86f68a4318ee8a953524d6c67baac5.png

2. PHP:OCI8的CURD

PHP对Clob文件是以resource的类型存取的, 所以PDO对Clob资源文件的读取应该这样操作:

$arr = $pdo -> fetch();

is_resource($arr[‘clob’]) && $arr[‘clob’]=stream_get_contents($arr[‘clob’]);

可以对照参考:PHP:OCI8 手册

更多CURD的Examples可以参考 官方范例

$c1 = oci_connect("hr", "welcome", 'localhost/XE');

$c2 = oci_connect("hr", "welcome", 'localhost/XE');

// Both $c1 and $c2 show the same PHP resource id meaning they use the

// same underlying database connection

echo "c1 is $c1

\n";

echo "c2 is $c2

\n";

function create_table($conn)

{

$stmt = oci_parse($conn, "create table hallo (test varchar2(64))");

oci_execute($stmt);

echo "Created table

\n";

}

function drop_table($conn)

{

$stmt = oci_parse($conn, "drop table hallo");

oci_execute($stmt);

echo "Dropped table

\n";

}

function insert_data($connname, $conn)

{

$stmt = oci_parse($conn, "insert into hallo

values(to_char(sysdate,'DD-MON-YY HH24:MI:SS'))");

oci_execute($stmt, OCI_DEFAULT);

echo "$connname inserted row without committing

\n";

}

function rollback($connname, $conn)

{

oci_rollback($conn);

echo "$connname rollback

\n";

}

function select_data($connname, $conn)

{

$stmt = oci_parse($conn, "select * from hallo");

oci_execute($stmt, OCI_DEFAULT);

echo "$connname ----selecting

\n";

while (oci_fetch($stmt)) {

echo " " . oci_result($stmt, "TEST") . "

\n";

}

echo "$connname ----done

\n";

}

create_table($c1);

insert_data('c1', $c1); // Insert a row using c1

sleep(2); // sleep to show a different timestamp for the 2nd row

insert_data('c2', $c2); // Insert a row using c2

select_data('c1', $c1); // Results of both inserts are returned

select_data('c2', $c2); // Results of both inserts are returned

rollback('c1', $c1); // Rollback using c1

select_data('c1', $c1); // Both inserts have been rolled back

select_data('c2', $c2);

drop_table($c1);

// Closing one of the connections makes the PHP variable unusable, but

// the other could be used

oci_close($c1);

echo "c1 is $c1

\n";

echo "c2 is $c2

\n";

// Output is:

// c1 is Resource id #5

// c2 is Resource id #5

// Created table

// c1 inserted row without committing

// c2 inserted row without committing

// c1 ----selecting

// 09-DEC-09 12:14:43

// 09-DEC-09 12:14:45

// c1 ----done

// c2 ----selecting

// 09-DEC-09 12:14:43

// 09-DEC-09 12:14:45

// c2 ----done

// c1 rollback

// c1 ----selecting

// c1 ----done

// c2 ----selecting

// c2 ----done

// Dropped table

// c1 is

// c2 is Resource id #5

?>

注意:

1.[oci_connect()]连接数据库时,为了防止乱码,建立连接的时候就指定字符编码。

// OCILogon 是oci_connect的别名, 不建议使用OCILogon

oci_connect($username, $password, $dbsid, $charset);

OCILogon($username, $password, $dbsid, $charset);

2.oci_execute() 执行一条之前被解析过的语句(见 oci_parse())。可选参数 mode 允许定义执行模式(默认是 OCI_COMMIT_ON_SUCCESS)。如果不需要将语句自动提交,则需要把 mode 设为 OCI_DEFAULT。

用 OCI_DEFAULT 模式时,将建立一个事务。事务会在关闭连接或脚本结束时(看哪个先)自动回卷。需要明确调用 oci_commit() 来提交事务,或者 oci_rollback() 中止事务。

成功时返回 TRUE, 或者在失败时返回 FALSE。

3. ThinkPHP 的Oracle Clob操作类:

[引用自ThinkPHP社区《分享自己的oracel类,支持多CLOB操作及主键自增加》]

class Ociclob{

var $conn;

var $table;

var $seqname;

var $where;//查询条件,字符串

var $lob;//lob字段名,数组

var $data;//数据数组

//架构函数

public function Ociclob($table='',$data=''){

//取TP框架的数据库配置

$this->connect(C('DB_USER'),C('DB_PWD'),C('DB_NAME'));

if(!empty($table)) $this->table=$table;

if(!empty($table)&&!empty($data)){

$this->checkfield($table,$data);

}

}

//检测字段属性

public function checkfield($table,$data){

if(!empty($table)&&!empty($data)){

$fields=$this->getFields($table);

foreach ($data as $key=>$value){

//检测lob字段

if(strtolower($fields[strtolower($key)]['type'])=='clob') $lob[]=$key;

//检测PK字段并获取SEQ

if(strtolower($fields[strtolower($key)]['primary'])==1){

$this->seqname=$value;

$this->data[$key]=$this->getseq();//根据自动填充主键值

$pk=$key;//主键被设置标志

}

}

$this->lob=$lob;

//如果没有在DATA中的设置主键值,则根据SEQNAME自动填充

if(!isset($pk)&&!empty($this->seqname)) {

$this->data[$fields['pk']]=$this->getseq();

}

unset($lob);

unset($pk);

}

}

/**

+----------------------------------------------------------

* 连接ORACLE

+----------------------------------------------------------

*/

public function connect($user, $password, $SID){

// 创建连接,并设置字符编码为'UTF8'.

$this->conn = OCILogon($user, $password, $SID, 'UTF8');

}

/**

+----------------------------------------------------------

* 设置ORACLE字符集

+----------------------------------------------------------

*/

public function charset($code='UTF8'){

$sql="ALTER DATABASE CHARACTER SET $code";

$stmt = oci_parse($this->conn, $sql);

oci_execute($stmt);

oci_commit($this->conn);

// Free resources

oci_free_statement($stmt);

}

/**

+----------------------------------------------------------

* 添加包含有CLOB字段的记录

+----------------------------------------------------------

*/

public function insert (){

//检测字段属性

if(empty($this->lob)) $this->checkfield($this->table,$this->data);

//字段整理

$f=strtoupper(join(',',array_keys($this->data)));

//数据整理

foreach ($this->data as $key=>$val){

$f_v_arr[]=!in_array($key,$this->lob)?"'".$val."'":"EMPTY_CLOB()";

}

$f_v=join(',',$f_v_arr);

//lob字段清理并赋值LOB数据到绑定变量

for ($i=0;$i$this->lob);$i++){

$lob_str.=":".$this->lob[$i]."_loc,";

}

$returning_str.=" RETURNING ".join(',',$this->lob)." INTO ".rtrim($lob_str,',');

//组装SQL

$sql = "INSERT INTO $this->table ($f) VALUES (".$f_v.")".$returning_str ;

$stmt = oci_parse($this->conn, $sql);

for ($i=0;$i$this->lob);$i++){

// 创建一个“空”的OCI LOB对象绑定到定位器

$$this->lob[$i] = oci_new_descriptor($this->conn, OCI_D_LOB);

$lob_str=":".$this->lob[$i]."_loc";

// 将Oracle LOB定位器绑定到PHP LOB对象

oci_bind_by_name($stmt, $lob_str, $$this->lob[$i], -1, OCI_B_CLOB);

}

// 执行该语句的使用,oci_default -作为一个事务

oci_execute($stmt, OCI_DEFAULT) or die ("Unable to execute query\n");

// 保存LOB对象数据

for ($i=0;$i$this->lob);$i++){

if(!$$this->lob[$i]->save($this->data[$this->lob[$i]])){

$result=false;

break;

}

}

if ( isset($result)&&$result==false ) {

// 如果错误,则回滚事务

oci_rollback($this->conn);

$ret=false;

} else {

// 如果成功,则提交

oci_commit($this->conn);

$ret=true;

}

// 释放资源

oci_free_statement($stmt);

for ($i=0;$i$this->lob);$i++){

$$this->lob[$i]->free();

}

return $ret;

}

/**

+----------------------------------------------------------

* 更新CLOB字段的内容

+----------------------------------------------------------

*/

public function update (){

//检测字段属性

if(empty($this->lob)) $this->checkfield($this->table,$this->data);

//数据整理

foreach ($this->data as $key=>$val){

$set_arr[]=!in_array($key,$this->lob)?strtoupper($key)."='".$val."'":$key."=EMPTY_CLOB()";

}

$set_str=join(',',$set_arr);

//lob字段清理并赋值LOB数据到绑定变量

for ($i=0;$i$this->lob);$i++){

$lob_str.=":".$this->lob[$i]."_loc,";

}

$returning_str.=" RETURNING ".join(',',$this->lob)." INTO ".rtrim($lob_str,',');

$where_str=strtoupper($this->where);

//组装SQL

$sql = "UPDATE $this->table SET $set_str WHERE $where_str ".$returning_str;

$stmt = OCIParse($this->conn, $sql);

for ($i=0;$i$this->lob);$i++){

// 创建一个“空”的OCI LOB对象绑定到定位器

$$this->lob[$i] = OCINewDescriptor($this->conn, OCI_D_LOB);

$lob_str=":".$this->lob[$i]."_loc";

// 将Oracle LOB定位器绑定到PHP LOB对象

OCIBindByName($stmt, $lob_str, $$this->lob[$i], -1, OCI_B_CLOB);

}

// 执行该语句的使用,oci_default -作为一个事务

OCIExecute($stmt, OCI_DEFAULT) or die ("Unable to execute query\n");

// 保存LOB对象数据

for ($i=0;$i$this->lob);$i++){

if(!$$this->lob[$i]->save($this->data[$this->lob[$i]])){

$result=false;

break;

}

}

if ( isset($result)&&$result==false ) {

OCIRollback($this->conn);

$ret=false;

}else $ret=true;

// 提交事务

OCICommit($this->conn);

//释放资源

for ($i=0;$i$this->lob);$i++){

$$this->lob[$i]->free();

}

OCIFreeStatement($stmt);

return $ret;

}

public function getseq(){

$sql="select $this->seqname.currval from dual";

$stmt = oci_parse($this->conn, strtoupper($sql));

oci_execute($stmt);

$data = array();

while ( $row = oci_fetch_array($stmt, OCI_ASSOC+OCI_RETURN_LOBS) ) {

if($row == null) continue;

array_push($data, $row);

}

// 释放资源

oci_free_statement($stmt);

array_filter($data);

return $data[0]['CURRVAL'];

}

/**

+----------------------------------------------------------

* 查询包含有CLOB字段的记录

+----------------------------------------------------------

*/

public function select ($sql=''){

$sql = empty($sql) ? "SELECT * FROM $this->table WHERE $this->where ":$sql;

$stmt = oci_parse($this->conn, strtoupper($sql));

oci_execute($stmt);

while ( $row = oci_fetch_array($stmt, OCI_ASSOC+OCI_RETURN_LOBS) ) {

$data[]=$row;

}

// 释放资源

oci_free_statement($stmt);

return $data;

}

/**

* 取得数据表的字段信息

*@access public

*/

public function getFields($tableName) {

$sql="select a.column_name,data_type,decode(nullable,'Y',0,1) notnull,data_default,decode(a.column_name,b.column_name,1,0) pk "

."from user_tab_columns a,(select column_name from user_constraints c,user_cons_columns col "

."where c.constraint_name=col.constraint_name and c.constraint_type='P'and c.table_name='".strtoupper($tableName)

."') b where table_name='".strtoupper($tableName)."' and a.column_name=b.column_name(+)";

$result= $this->select ($sql);

$info = array();

if($result) {

foreach ($result as $key => $val) {

$info[strtolower($val['COLUMN_NAME'])] = array(

'name' => strtolower($val['COLUMN_NAME']),

'type' => strtolower($val['DATA_TYPE']),

'notnull' => $val['NOTNULL'],

'default' => $val['DATA_DEFAULT'],

'primary' => $val['PK'],

'autoinc' => $val['PK'],

);

if($val['PK']==1) $info['pk']=$val['COLUMN_NAME'];

}

}

return $info;

}

}

?>

Ociclob 的调用样例:

假设已经存在一个表名为’tb_post’的表(表的主键为’postid’,并且是自增的),以及一个名为’SEQ_POST’的序列名

/**

* $data 要插入到表的数据

* 返回值 插入数据的ID

*/

function insertPostWithClob($data) {

$clog_obj=new Ociclob();

$clog_obj->table='tb_post';

$clog_obj->seqname='SEQ_POST';

$clog_obj->data = $data;

if($clog_obj->insert() == false) return -1;

$ret = $clog_obj->getseq();

return $ret;

}

/**

* $data 要插入到表的数据

* 返回值 是否修改成功

*/

function updatePostWithClob($data) {

$postid = $data['postid'];

$clog_obj=new Ociclob();

$clog_obj->table='tb_post';

$clog_obj->where="postid='$postid'";

$clog_obj->data = $data;

return $clog_obj->update();

}

/**

* $postid

* 返回值 查询得到的list

*/

function selectPostWithClob($postid) {

$clog_obj=new Ociclob();

$clog_obj->table='tb_post';

$clog_obj->where="postid='$postid'";

$ret=$clog_obj->select();

return $ret;

}

4. 参考资料:

ThinkPHP社区《分享自己的oracel类,支持多CLOB操作及主键自增加》

[PHP Manual OCI8函数介绍]

[oracle 官网的解释]

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值