用PHP操纵Oracle的LOB类型的数据

 更新时间:2016年11月25日 16:40  点击:1808

用过Oracle的人都知道,Oracle有一种数据类型叫VARCHAR2,用来表示不定长的字符串。VARCHAR2也是Oracle公司推荐使用的类型。但使用VARCHAR2有个问题:最大只能表示4000个字符,也就相当于2000个汉字。假如你的程序中某个字符的值要大于20002个汉字,用VARCHAR2就不能满足要求了。这时候,你有两个选择,一是用多个VARCHAR2来表示,二是用LOB字段。这里我们来看看第二个办法。

  先来大体了解一下Oracle的LOB字段。Oracle的LOB类型分为三种:BLOB,CLOB和BFILE。CLOB称为字符LOB,BLOB和BFILE是用来存储二进制数据的。CLOB和BLOB的最大长度是4GB,它们把值存放在Oracle数据库中。BFILE和BLOB类似,但它把数据放在外部的文件中,所以它又称为外部BLOB(External BLOB)。

  我想,我们对MYSQL应该都不会生疏。MYSQL中也有类似的数据类型,如TEXT和BLOB。在PHP的MYSQL函数中,对TEXT/BLOB的操作是直接的,就象其它类型的数据一样。但在Oracle中,情况就不一样了。Oracle把LOB当作一种非凡的数据类型来处理,在操作上不能用常规的方法。比如,不能在INSERT语句中直接把值插入到LOB字段中,也不能用LIKE进行查找。

  下面就通过几个例子来说明如何用PHP的OCI函数来插入,取出和查询LOB数据。

  插入

  不能直接用INSERT语句向LOB字段中插入值。一般情况下,有如下的几步:

  1、先分析一个INSERT语句,返回一个LOB的描述符

  2、用OCI函数生成一个本地的LOB对象

  3、将LOB对象绑定到LOB描述符上

  4、执行INSERT语句

  5、给LOB对象赋值

  6、释放LOB对象和SQL语句句柄

  下面的这个例子是把用户上传的图片文件存放到BLOB(或BFILE中,操作稍有不同)中。首先要建一个表,结构如下:


CREATE TABLE PICTURES (
ID NUMBER,
DESCRIPTION VARCHAR2(100),
MIME VARCHAR2(128),
PICTURE BLOB
);

  假如要实现ID的自动增加,再建一个SEQUENCE:


CREATE SEQUENCE PIC_SEQ;

  然后是用来处理数据的PHP程序代码。


<?php

 //建立Oracle数据库连接

 $conn = OCILogon($user, $password, $SID);

 //提交SQL语句给Oracle
 //在这里要注重的两点:一是用EMPTY_BLOB()函数。这是Oracle的内部函数,返回一个LOB的定位符。在插入LOB时,只能用这个办法先生成一个空的LOB定位符,然后对这个定位符进行操作。EMPTY_BLOB()函数是针对BLOB类型的,对应于CLOB的是EMPTY_CLOB()。二是RETURNING后面的部分,把picture返回,让PHP的OCI函数能够处理。

 $stmt = OCIParse($conn,"INSERT INTO PICTURES (id, description, picture)
VALUES (pic_seq.NEXTVAL, '$description', '$lob_upload_type', EMPTY_BLOB()) RETURNING picture INTO :PICTURE");

 //生成一个本地LOB对象的描述符。注重函数的第二个参数:OCI_D_LOB,表示生成一个LOB对象。其它可能的还有OCI_D_FILE和OCI_D_ROWID,分别对应于BFILE和ROWID对象。

 $lob = OCINewDescriptor($conn, OCI_D_LOB);

 //将生成的LOB对象绑定到前面SQL语句返回的定位符上。

 OCIBindByName($stmt, ':PICTURE', &$lob, -1, OCI_B_BLOB);
 OCIExecute($stmt);

 //向LOB对象中存入数据。因为这里的源数据是一个文件,所以直接用LOB对象的savefile()方法。LOB对象的其它方法还有:save()和load(),分别用来保存和取出数据。但BFILE类型只有一个方法就是save()

 if($lob->savefile($lob_upload)){
  OCICommit($conn);
  echo "上传成功<br>";
 }else{
  echo "上传失败<br>";
 }
//释放LOB对象

当今大多数 Web 应用程序都需要至少采用某种基本的安全策略。例如,提供用口令保护的内容的网站、仅具有治理员后端的网站、网志和个人杂志、电子商务网站、企业内联网,等等。
  

  构建这些类型的 Web 应用程序最常用的设计方法是将安全策略整合到 Web 应用程序的业务逻辑中,即由应用程序决定某个用户是否有权访问数据库中的某个数据。在这种情形下,数据库的角色仅为存储数据和依请求提供数据。换句话说,假如 Web 应用程序命令数据库提供特定信息,则数据库会直接执行该命令而不检查用户的权限。


  在该文中,您将学习如何利用 Oracle 内置的安全特性在数据库级执行应用程序安全规则,以提高应用程序的整体安全性。作为附带的好处,直接在数据库中实现数据访问安全不但有助于提高应用程的安全性,而且有助于降低复杂性。


  对数据库端安全性的需求


  从 Web 应用程序控制数据访问会怎么样?大多数情况下没有问题;这是个不错的解决方案,尤其是在涉及的数据为非任务要害或绝密的时候。许多书和在线资源中都用到了该方法。实际上,有本很受欢迎的 PHP/MySQL 书明确反对每个应用程序创建一个以上的数据库用户帐户,这是因为“额外的用户或复杂的权限会因某个操作在继续前要检查更多的信息而降低 MySQL 的执行速度”。确实如此;但是,在放弃将安全性整合到数据库逻辑中的想法前可能要考虑几件事情。我们来看以下示例。


  假设创建一个内容治理系统 (CMS)。其中使用数据库来存储网站上发布的内容。大部分数据是公开的,答应匿名 Web 用户读取;但只答应编辑更改数据。使用单一数据库帐户访问和修改数据库中的记录,并通过用口令保护仅治理员可以访问的页面的访问权限用 PHP 代码控制安全性。


  假如 Web 应用程序的公共端遭受了一个诸如公共搜索表单(即编码不够严密的表单)上的 SQL 注入的攻击,则该入侵者可能能够对该公共帐户可以访问的数据库对象执行任意 SQL 语句。当然,就这里的情形而言,执行 SELECT 语句不会造成什么大问题,这是因为数据本来就是公共的。但由于公共权限和治理权限使用同一数据库帐户,因此入侵者还能执行 UPDATE 和 DELETE 语句,甚至是从数据库中删除表。


  怎么才能防止该情况的发生呢?最简单的方法就是彻底限制公共数据库帐户修改数据的权限。我们来看看 Oracle 是如何解决这个问题的。


  Oracle 安全性基本概述


  Oracle 数据库为 Web 开发人员提供了控制数据访问的许多方法,从治理对特定数据库对象(如表、视图和过程)的访问到控制个别行或列的数据的访问。很显然,对 Oracle 每个安全特性或可用选项的讨论超出了本文的范围。在这里,我们将不涉及过多细节,而仅介绍 Oracle 数据访问安全性的最基本方面:


  验证和用户帐户


  权限


  角色


  验证和用户帐户。 与其他数据库一样,请求访问 Oracle 的每个用户(数据库帐户)必须通过验证。验证工作可以由数据库、操作系统或网络服务来做。除基本的验证(口令验证)外,Oracle 还支持强验证机制,如Kerberos、CyberSafe、RADIUS,等等。


  角色。 Oracle 角色是一个权限的有名集。尽管可以直接授予用户帐户权限,但使用角色可以极大简化用户治理,尤其是需要治理大量用户时。创建易治理的小角色,然后根据用户的安全级别授予用户一个或多个角色,这样做的效率非常高。更不用说修改权限变得如何简单了

1、分号的例外

  在MySQL中,每一行命令都是用分号(;)作为结束的,但是当一行MySQL命令被插入在PHP代码中时,最好把后面的分号省略掉,例如:

mysql_query ("INSERT INTO tablename (first_name, last_name) VALUES ('$first_name', '$last_name')");

  这是因为PHP也是以分号作为一行的结束的,额外的分号有时会导致PHP 的语法分析器做出错误的分析,所以还是省略掉的好。在这种情况下,虽然省略了分号,但是 PHP 在执行 MySQL 命令时会自动加上分号。

  另外还有一个不要加分号的情况。当你想把要字段的竖着排列显示下来,而不是像通常的那样横着排列时,你可以用 G 来结束一行SQL 语句,这时就用不上分号了,例如:

    SELECT * FROM PENPALS WHERE USER_ID = 1G

  2、TEXT、DATE、和 SET 数据类型

  TEXT 不是一种数据类型,应该是" LONG VARCHAR "或者" MEDIUMTEXT "。

  DATE 数据类型的格式是 YYYY-MM-DD ,比如: 2001-10-01 。你可以很轻易的用 date 函数来得到这种格式的当前系统时间:

    date("Y-m-d")

  并且,在 DATA 数据类型之间可以作减法,得到相差的时间天数:

    $age = ($current_date - $birthdate);

  集合 SET 是一个有用的数据类型,它和枚举 ENUM 有点相似,只不过是 SET 能够保存多个值而 ENUM 只能保存一个值而已。而且, SET 类型最多只能够有 64 个预定的值,而 ENUM 类型却能够处理最多 65,535 个预定义的值。而假如需要有大于 64 个值的集合,该怎么办呢?这时就需要定义多个集合来一起解决这个问题了。

  3、通配符

  SQL 的通配符有两种:" * "和" % "。分别用在不同的情况下。例如:假如你想看到数据库的所有内容,可以像这样来查询:

    SELECT * FROM dbname WHERE USER_ID LIKE '%';

  这儿,两个通配符都被用上了。他们表示相同的意思 ?? 都是用来匹配任何的字符串,但是他们用在不同的上下文中。" * "用来匹配字段名,而" % "用来匹配字段值。另外一个不轻易引起注重的地方是" % "通配符需要和 LIKE 要害字一起使用。

  还有一个通配符,就是下划线" _ ",它代表的意思和上面不同,是用来匹配任何单个的字符的。

  4、NOT NULL 和空记录

  假如用户在没有填任何东西的情况下按了 submit 按钮,会怎样呢?假如你确实需要一个值,那么可以用客户端脚本或者服务器端脚本来进行数据验证,这一点在前面已经说过了。但是,在数据库中却是答应一些字段被空出来什么也不填。对此类纪录, MySQL 将进行以下步骤:

  插入值 NULL ,这是缺省的操作。

  假如你在字段定义中为之声明了 NOT NULL (在建立或者修改这个字段的时候), MySQL 将把这个字段空出来什么东西也不填。

  对于一个 ENUM 枚举类型的字段,假如你为之声明了 NOT NULL , MySQL 将把枚举集的第一个值插入到字段中。也就是说, MySQL 把枚举集的第一个值作为这个枚举类型的缺省值。

  一个值为 NULL 的纪录和一个空纪录是有一些区别的。 % 通配符可以匹配空纪录,但是却不能匹配 NULL 纪录。在某些时候,这种区别会造成一些意想不到的后果。就经验而言,任何字段都应该声明为 NOT NULL 。这样下面的 SELECT 查询语句就能够正常运转了:

  if (!$CITY) {$CITY = "%";}
  $selectresult = mysql_query ("SELECT * FROM dbname
  WHERE FIRST_NAME = ' Bill '
  AND LAST_NAME = ' Gates '
  AND CITY LIKE '$CITY'
  ");

  在第一行中,假如用户没有指定一个 CITY 值,那么就会用通配符 % 来代入 CITY 变量,这样搜索时就会把任何的 CITY 值都考虑进去,甚至包括那些 CITY 字段为空的纪录。

  但是假如有一些纪录,它的 CITY 字段值是 NULL ,这时问题就出现了。上面的查询是不能够找到这些字段的。问题的一个解决办法可以是这样:

  if (!$CITY) {$CITY = "%";}
  $selectresult = mysql_query ("SELECT * FROM dbname
  WHERE FIRST_NAME = ' Bill '
  AND LAST_NAME = ' Gates '
  AND (CITY LIKE '$CITY' OR CITY IS NULL)
  ");

  注重在搜索 NULL 时,必须用" IS "要害字,而 LIKE 时不会正常工作的。

  在最后要提到的是,假如你在加入或者修改一个新的字段之前,数据库中已经有了一些记录了,这时新加入的字段在原来的纪录中的值,可能是 NULL ,也可能为空,在这种情况下,使用 SELECT 查询要非凡的小心。

通过一个小时的研究和设置.实现了最新的 PHP 5.0 MYSQL 5.0 WIN2003.
个人认为还是有必要写个教程出来.因为很多方面和老版本的不尽相同.
说实话自己也是查阅了很多官方文档才解决了很多怪异问题.

=========================

MYSQL 5.0 FOR WINDOWS
PHP 5.0 FOR WINDOWS
PHPMYADMIN
WINDOWS SERVER 2003

=========================

首先安装 MYSQL .本来以为新版本的安装界面应该会花哨点.
但是仍然只看到老土的海豚.除了安装时间比 4.0 长.当然咯.因为 5.0 比 4.0 体积大很多.

推荐安装在独立的 NTFS 分区上.比如我服务器的 F盘.只放服务器软件.
路径为: F:MYSQL

然后进入 F:MYSQLBIN 鼠标双点 winmysqladmin.exe
首次运行会提示输入超级用户和密码.就输入 root 密码 root
注重啊.假如是对外服务器请设置超级复杂.比如 Wjwsfjn29szjwh~mysql
翻译过来就是: 我叫魏舒芬.今年29岁至今未婚.

到这里.MYSQL就安装完毕了.假如不明白请参看深空同学的相关文章.

=========================


下面安装 PHP 5.0 其实没什么安装不安装的.解压缩文件.推荐放到
路径为: F:PHP

到这里就应该进入要害步骤了.
首先复制 PHP 目录下的 Php.ini-dist 到 C:Windows 并将文件名修改成为 Php.ini

COPY F:PHPPhp.ini-dist C:Windows
Ren Php.ini-dist Php.ini

假如是 WINDOWS 2000 就是: C:WINNT
假如是 WIN9X / 2003 就是: C:Windows

然后复制 PHP 目录下 DLLS 目录里的所有文件到 SYSTEM32 目录.

COPY F:PHPdlls*.* C:WindowsSystem32

假如是 WINDOWS 2000 就是: C:WINNTSystem32
假如是 WIN9X / 2003 就是: C:WindowsSystem32

继续.复制PHP目录下 php4ts.dll 文件到 System32 目录里.

COPY F:PHPphp4ts.dll to C:WindowsSystem32

=========================

//在PHP中处理日期非常不方便,比如求两个日期之间相差的月份?该怎么办呢?
  //文件名:date.inc.php3
  //在使用这两个函数前,要先将日期或日期时间转换成timestamp类型。
  //如:
  //$today=mktime(0,0,0,date("m"),date("d"),date("Y"));

  /****模拟sqlserver中的dateadd函数*******
  $part 类型:string
  取值范围:year,month,day,hour,min,sec
  表示:要增加的日期的哪个部分
  $n 类型:数值
  表示:要增加多少,根据$part决定增加哪个部分
  可为负数
  $datetime类型:timestamp
  表示:增加的基数
  返回 类型:timestamp

  **************结束**************/

function dateadd($part,$n,$datetime){
$year=date("Y",$datetime);
$month=date("m",$datetime);
$day=date("d",$datetime);
$hour=date("H",$datetime);
$min=date("i",$datetime);
$sec=date("s",$datetime);
$part=strtolower($part);
$ret=0;
switch ($part) {
case "year":
$year =$n;
break;
case "month":
$month =$n;
break;
case "day":
$day =$n;
break;
case "hour":
$hour =$n;
break;
case "min":
$min =$n;
break;
case "sec":
$sec =$n;
break;
default:
return $ret;
break;
}
$ret=mktime($hour,$min,$sec,$month,$day,$year);
return $ret;
}

[!--infotagslink--]

相关文章

  • C#连接SQL数据库和查询数据功能的操作技巧

    本文给大家分享C#连接SQL数据库和查询数据功能的操作技巧,本文通过图文并茂的形式给大家介绍的非常详细,需要的朋友参考下吧...2021-05-17
  • php简单数据操作的实例

    最基础的对数据的增加删除修改操作实例,菜鸟们收了吧...2013-09-26
  • 解决Mybatis 大数据量的批量insert问题

    这篇文章主要介绍了解决Mybatis 大数据量的批量insert问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-01-09
  • php中浮点型(float)和整型(integer)数据类型详解

    文章分析了关于php中浮点型(float)和整型(integer)数据类型的用法区别以及在那种情况下会出现数据长度不够。 取值只能为True或者False,当其他类型转化为boolean类...2016-11-25
  • Antd-vue Table组件添加Click事件,实现点击某行数据教程

    这篇文章主要介绍了Antd-vue Table组件添加Click事件,实现点击某行数据教程,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-11-17
  • 详解如何清理redis集群的所有数据

    这篇文章主要介绍了详解如何清理redis集群的所有数据,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-18
  • vue 获取到数据但却渲染不到页面上的解决方法

    这篇文章主要介绍了vue 获取到数据但却渲染不到页面上的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-11-19
  • Javascript类型转换的规则实例解析

    这篇文章主要介绍了Javascript类型转换的规则实例解析,涉及到javascript类型转换相关知识,对本文感兴趣的朋友一起学习吧...2016-02-27
  • c# 数据类型占用的字节数介绍

    本篇文章主要是对c#中数据类型占用的字节数进行了详细的介绍。需要的朋友可以过来参考下,希望对大家有所帮助...2020-06-25
  • php把读取xml 文档并转换成json数据代码

    在php中解析xml文档用专门的函数domdocument来处理,把json在php中也有相关的处理函数,我们要把数据xml 数据存到一个数据再用json_encode直接换成json数据就OK了。...2016-11-25
  • mybatis-plus 处理大数据插入太慢的解决

    这篇文章主要介绍了mybatis-plus 处理大数据插入太慢的解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2020-12-18
  • postgresql数据添加两个字段联合唯一的操作

    这篇文章主要介绍了postgresql数据添加两个字段联合唯一的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-02-04
  • Oracle使用like查询时对下划线的处理方法

    这篇文章主要介绍了Oracle使用like查询时对下划线的处理方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下...2021-03-16
  • Vue生命周期activated之返回上一页不重新请求数据操作

    这篇文章主要介绍了Vue生命周期activated之返回上一页不重新请求数据操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-07-26
  • JQuery.Ajax()的data参数类型实例详解

    假如现在有这样一个表单,是添加元素用的。<form id='addForm' action='UserAdd.action' type='post'> <label for='uname'>用户名</label>:<input type='text' name='uname' id='uname'><br>...2015-11-24
  • 深入理解PHP变量的值类型和引用类型

    在PHP中,大部分变量类型,如字符串,整型,浮点,数组等都是值类型的,而类和对象是引用类型,在使用的时候,需要注意这一点。看到网友在讨论PHP的&符号,要彻底理解它的用法,就有必要讨论一下变量的两种形式。PHP的变量在内存中是这样...2015-10-23
  • 解决vue watch数据的方法被调用了两次的问题

    这篇文章主要介绍了解决vue watch数据的方法被调用了两次的问题,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2020-11-07
  • Javascript中的数据类型之旅

    虽然Javascript是弱类型语言,但是,它也有自己的几种数据类型,分别是:Number、String、Boolean、Object、Udefined、Null。其中,Object属于复杂数据类型,Object 由无序的键值对组成。其余几种都属于简单数据类型。注意:变量...2015-10-21
  • c# socket网络编程接收发送数据示例代码

    这篇文章主要介绍了c# socket网络编程,server端接收,client端发送数据,大家参考使用吧...2020-06-25
  • vue 数据(data)赋值问题的解决方案

    这篇文章主要介绍了vue 数据(data)赋值问题的解决方案,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-29