使用php调用oracle数据库的几篇参考文章

经过和ci框架自带oci8 driver的多次挣扎,果断放弃了自带类(但是项目中有个恶心的牺牲点,这里就不恶心大家了..以后有空了我会回来改的….).找到几篇php调用oracle存储过程的参考文章,并且根据这几篇文章中提到的提示,成功解决了项目中的问题,特此马克一下文章地址,方便以后学习整理.

 

1. oracle中文官网的这篇文章范例还是很详尽的,但是部分oci_方法已经在php5之后做了些许修改,因此建议再查找php的官方手册进行对比学习

http://www.oracle.com/technetwork/cn/articles/fuecks-sps-082839-zhs.html

 

2.Call Oracle (oci8) store procedure from Codeigniter 国外被墙blog里面的一篇讲解通过pdo_oci8去使用oracle存储过程的详细说明

http://manasbala.wordpress.com/2012/03/20/call-oracle-oci8-store-procedure-from-codeigniter/

 

3.php官方权威手册的oci8操作指南,不得不说,这块冷门资料官方的example还是依旧非常详细.

http://www.php.net/manual/en/ref.oci8.php

 

Read More

浅浅浅谈一点点最基础的php安全知识

1.永远不要相信来自用户的任何数据!
       不要相信使用你产品的用户都是各种小白,更何况,即使是小白都有可能在不经意间提交了不正常的数据导致此次甚至于整个系统的崩溃.严格处理数据的验证,严格控制数据流,是任何web后端语言都必须做到的事情.同时,很重要的一点别把系统的安全验证都交给前端工程师,正确的做法是前端和后台都要做相应的验证! 说到这里笔者不经意又想起来一号店的支付bug给笔者带来了无数次的方便,这个bug就和此类问题有关.
       所以说,虽然这一点是一个老生常谈的话题了,但是很多程序员在自己的程序中总能出现这类问题,所以这里又将他放在了第一点,重点给还未加入php 或 刚步入php学习的童鞋们一个提醒.

那么此问题到底有什么具体的措施可以防范的呢? 答案也很简单,为了确保安全性和健壮性,数据验证时应该主要从以下四点方面进行着手:
       (1) 关键数据是否存在。如删除数据id是否存在

       (2) 数据类型是否正确。如删除数据id是否是整数

       (3) 数据长度。如字段是char(10)类型则要strlen判断数据长度

       (4) 数据是否有危险字符

        在针对以上问题进行处理时,对于数据的可通过性,我们常考虑使用黑名单阻拦(Black-listed value forbidden)或白名单通过(White-listed value passed)两种方式进行处理.两者之间的区别是:通常在进行验证数据时,可能值的列表或范围小于无效值的列表或范围,其中许多值可能是未知值或意外值.
        其实对于上面说到的两种验证数据的常用方式,不过是几个判断或者几个分支语句的运用,这个几乎是没有任何技术门槛的问题,主要还是作为开发者的安全意识问题.这里就不累赘地举各种低端的没意思的代码实例了.
        然后,最后建议是安全数据过滤在开发时同步进行考虑,不要等业务逻辑都完成之后再单独考虑安全过滤等问题,此时再介入考虑可能会带来更多潜在的问题.虽然笔者只是90后,但是接触php的时间也比较早,初中的时候由asp转型到php后也做了不少大中小型的php应用接触了各种开发框架,经过尝试各种解决php数据安全验证的方式,笔者认为这种方式是最佳的了.

接下来再举几个关于数据安全方面的重点:


(1) 入库数据必须要进行严格的验证.
       所有$_POST/$_GET/$_REQUEST/$_SERVER等都不可以直接丢给类函数(当然,除了验证或过滤类),即使是使用框架,或框架内自带了对于post和get的自动过滤功能,也建议你把他关掉然后通过自己来处理每个post和get.因为框架内把每次的post和get都进行重复的过滤,在效率上本身就很有问题,只是提供给某些低端phper的一种方案不建议大家使用!

       其次,对于我后面说到的$_REQUEST/$_SERVER可能有很多童鞋会觉得奇怪,特别是对$_SERVER,有人会说,这个都是服务器的变量了为什么还有可能不安全呢? 我可以明确告诉你,这个变量里面也可以轻易伪造,具体方式不细说,可以自行google. 同样,还有其他$_开头的php内置变量数组里面取到的数据都有可能被篡改,大家务必小心!


(2) 前端验证之后后台同样要验证!
        select,checkbox,radio,button等等用户不能直接输入的地方传值的验证经常会被忽略,但实际上,这些地方也是最好动手脚的,伪造一个表单value,妥妥的.

(3)  表单元素的name和数据库字段名务必差异化
        比如表单上的name是 username ,那么数据库里面的字段名就不可取 username . 但实践中,绝大部分低端phper们都是取一样的值,这无疑是主动给别人暴库也没什么差别了. 隐患虽小,但是引爆点很大!!

 

 

2.防注入


(a) 简单的判断是否存在注入漏洞?


访问某网址 http://www.xxxx.com/test.php?id=1 是正常展示了某页面,sql语句可以猜测大致如此:

SELECT  *  FROM table WHERE id = 1 

接着访问 http://www.xxxxx.com/test.php?id=1’ sql语句可能是:

SELECT * FROM table WHERE id = 1’

然后访问页面出现异常错误信息或页面空白的话,说明了test.php 文件没有对id的值进行“  ’”(上单引号) 过滤或者id的intval()进行整形转换,当然,接着你还可以用软件进行穷举其他字符如“%”,“/*”等。

继续访问 http://www.xxxx.com/test.php?id=1 and 1=1  则sql语句可能是

SELECT  *  FROM table WHERE id = 1 and 1=1

运行正常且结果和 http://www.xxxx.com/test.php?id=1 结果一样,则说明test.php可能没有对空格“ ”、和“and”过滤,接下来访问 http://www.xxxx.com/win.php?id=1 and 1=2  则sql语句可能是

SELECT  *  FROM table WHERE id = 1 and 1=2

如果运行结果异常说明sql语句中“and 1=2”起作用,所以能3个条件都满足都则很确定的test.php存在注入漏洞。

 

(b)最基础的防注入方式

      最简单的方法是使用php自带的两个自动转义函数 addslashes 和 stripslashes ,(其实htmlspecailchars被有人错误地拿来使用在防止注入问题上了,实际上他是最基础的解决xss的函数.请勿搞混.)

      addslashes是可以给传入数据中遇到的特殊字符进行自动转义,加上"\".stripsplashes函数相反他是把转义后的数据再还原回来的反转义函数.

      然后在这里有一个需要注意的,就是需要判断是否服务器上开启了 magic_quotes_gpc 如果他是on状态则不能再重复进行addsplashes,否则就会加上两个"\"之后就把数据搞乱了. 建议使用之前通过get_magic_quotes_gpc()函数检查是否开启本功能.

 

 

3.php安全配置方面的一些小细节


(a) 关闭php.ini 文件中的 display_errors ; 在生产环境中保证即使php代码出现错误,也不会把错误信息返回给用户,这样就不会让他们获取到服务器上的一些信息.保证了一定程度上的安全.或者在php文件头部加上 error_reporting(0);
(b) 关闭默认php配置中的不好的功能
php.ini中,设置 magic_quotes_gpc = off;
设置 register_globals = off; 保证如果程序中有未被初始化的变量不会被篡改,否则会造成致命的安全问题!
(c) 严格配置文件夹和文件权限,能用644就不用755,能用755就不用777!

Read More

从ob_start()作用谈到buffer和cache的区别

在学习php的过程中,有童鞋曾经看到过不下数十次这样的写法

<?php

ob_start();

echo “xxxxx”;

$test = “xxxxx”;

….

header(“location:http://………”);

ob_end_flush();

?>

若删除ob_start()之后,php肯定报错,告知发送header函数必须作为一条执行语句,然后就有童鞋产生误区,”我要在我写的乱七八糟的代码之后突然发送一个header或者set一个cookie的时候,我就用ob_start”.那么这种做法是最佳的吗?

显然肯定不是,虽然说ob_start可以曲线救国地实现上述的效果,但是每一次开启ob都会对I/O增加负担,仅仅是为了实现发送一条不符合规矩的header,这么做显然是得不偿失的.

那么到底ob_start有什么作用呢?先不着急.我们从什么是ob_start开始说起.

ob 指的是 output buffering ,翻译成中文可以理解成 输出缓冲 .说到这里,又会有童鞋想到 cache这个东西,说实话之前我对buffer和cache的理解也有偏差和误解(谁叫我是通信的而不是计算机的呢 = =!).今天借此机会正好记录一下自己对这块知识的补漏.那么cache和buffer分别是什么又有什么区别和作用呢?

 

首先 buffer是I/O缓存,用于内存<->硬盘之间的缓存;cache是高速缓冲,主用于CPU<->内存之间的缓冲.

cache 最简单地可以理解为高速地”读”,最初始于cpu cache,因为早时候cpu的处理速度远高于内存的频率速度,就会把一些经常用到的东西存入cpu cache中,直接从cache中调用比去内存中取要快得多. 然后cpu又有L1 L2 cache,分属不同工作层级,进一步实现性能的优化.

buffer 简单地理解为高速地”写”,把即将要写入硬盘的东西先存入buffer中,等待确认指令,当确认指令下达后才进行磁盘的写操作,间接保护硬盘,同时加速了文件在保存上的效率.

那么在回到php中来,这个ob_start自然是开启输出缓冲(这里的输出是相对于php来说,对于硬盘的话其实就是输入).把此函数执行之后的所有内容都存入buffer中去,等待处置.ob操作经常用于需要进行自定义的gzip压缩/字符数据的替换/捕获页面的整体输入出然后一次性写入生成静态HTML文件的作用.其中用的最广泛的就是生成静态文件.

最后再附上一篇参考文章,想进一步了解的童鞋可以到这里继续深入 http://developer.51cto.com/art/200912/166834.htm

Read More

dz x2.5中与7.2的重点用户表大致对应

随手记录一下

 

cdb_members对应新的pre_common_member

cdb_memberfields对应 pre_common_profile

 

字段设置略有改动,如果做通行证程序的时候注意此问题

 

 

记录x2.5的注册sql流程

/*!\C binary *//*!*/;
SET @@session.character_set_client=63,@@session.collation_connection=33,@@session.collation_server=33/*!*/;
INSERT INTO `redhomebbs`.cdb_uc_members SET secques=”, username=’kanghq2′, password=’d200a9c48eb4c38177af6571778b1419′, email=’kanghq2@qq.com’, regip=’192.168.120.185′, regdate=’1334381182′, salt=’e63def’
/*!*/;
# at 4316
#120414 13:26:22 server id 1 end_log_pos 4436 Query thread_id=284 exec_time=0 error_code=0
SET TIMESTAMP=1334381182/*!*/;
INSERT INTO `redhomebbs`.cdb_uc_memberfields SET uid=’124151′
/*!*/;
# at 4436
#120414 13:26:22 server id 1 end_log_pos 4736 Query thread_id=283 exec_time=0 error_code=0
use redhomebbs/*!*/;
SET TIMESTAMP=1334381182/*!*/;
REPLACE INTO pre_common_member SET `uid`=124151 , `username`=’kanghq2′ , `password`=’7ce5916a14125dcad401b05f4d5c02e8′ , `email`=’kanghq2@qq.com’ , `adminid`=0 , `groupid`=10 , `regdate`=1334381182 , `credits`=0 , `timeoffset`=9999
/*!*/;
# at 4736
#120414 13:26:22 server id 1 end_log_pos 5003 Query thread_id=283 exec_time=0 error_code=0
SET TIMESTAMP=1334381182/*!*/;
REPLACE INTO pre_common_member_status SET `uid`=124151 , `regip`=’192.168.120.185′ , `lastip`=’192.168.120.185′ , `lastvisit`=1334381182 , `lastactivity`=1334381182 , `lastpost`=0 , `lastsendmail`=0
/*!*/;
# at 5003
#120414 13:26:22 server id 1 end_log_pos 5269 Query thread_id=283 exec_time=0 error_code=0
SET TIMESTAMP=1334381182/*!*/;
REPLACE INTO pre_common_member_count SET `uid`=124151 , `extcredits1`=0 , `extcredits2`=0 , `extcredits3`=0 , `extcredits4`=0 , `extcredits5`=0 , `extcredits6`=0 , `extcredits7`=0 , `extcredits8`=0
/*!*/;
# at 5269
#120414 13:26:22 server id 1 end_log_pos 5393 Query thread_id=283 exec_time=0 error_code=0
SET TIMESTAMP=1334381182/*!*/;
REPLACE INTO pre_common_member_profile SET `uid`=124151
/*!*/;
# at 5393
#120414 13:26:22 server id 1 end_log_pos 5521 Query thread_id=283 exec_time=0 error_code=0
SET TIMESTAMP=1334381182/*!*/;
REPLACE INTO pre_common_member_field_forum SET `uid`=124151
/*!*/;
# at 5521
#120414 13:26:22 server id 1 end_log_pos 5648 Query thread_id=283 exec_time=0 error_code=0
SET TIMESTAMP=1334381182/*!*/;
REPLACE INTO pre_common_member_field_home SET `uid`=124151
/*!*/;
# at 5648
#120414 13:26:22 server id 1 end_log_pos 5893 Query thread_id=283 exec_time=0 error_code=0
SET TIMESTAMP=1334381182/*!*/;
REPLACE INTO pre_common_syscache SET `cname`=’userstats’ , `ctype`=1 , `dateline`=1334381182 , `data`=’a:2:{s:12:\”totalmembers\”;i:56788;s:10:\”newsetuser\”;s:7:\”kanghq2\”;}’
/*!*/;
# at 5893
#120414 13:26:22 server id 1 end_log_pos 6157 Query thread_id=283 exec_time=0 error_code=0
SET TIMESTAMP=1334381182/*!*/;
DELETE FROM pre_common_session WHERE sid=’8ciZpP’ OR lastactivity<1334379982 OR (uid=’0′ AND ip1=’192′ AND ip2=’168′ AND ip3=’120′ AND ip4=’185′ AND lastactivity>1334381122) OR (uid=’124151′)
/*!*/;
# at 6157
#120414 13:26:22 server id 1 end_log_pos 6499 Query thread_id=283 exec_time=0 error_code=0
SET TIMESTAMP=1334381182/*!*/;
INSERT INTO pre_common_session SET `sid`=’8ciZpP’ , `ip1`=’192′ , `ip2`=’168′ , `ip3`=’120′ , `ip4`=’185′ , `uid`=’124151′ , `username`=’kanghq2′ , `groupid`=’10’ , `invisible`=’0′ , `action`=0 , `lastactivity`=’1334381024′ , `lastolupdate`=’1334380201′ , `fid`=0 , `tid`=0
/*!*/;
# at 6499
#120414 13:26:22 server id 1 end_log_pos 6656 Query thread_id=283 exec_time=0 error_code=0
SET TIMESTAMP=1334381182/*!*/;
INSERT INTO pre_common_statuser SET `uid`=124151 , `daytime`=’20120414′ , `type`=’login’
/*!*/;
# at 6656
#120414 13:26:22 server id 1 end_log_pos 6798 Query thread_id=283 exec_time=0 error_code=0
SET TIMESTAMP=1334381182/*!*/;
UPDATE pre_common_stat SET `login`=`login`+1 WHERE `daytime` = ‘20120414’
/*!*/;
# at 6798
#120414 13:26:22 server id 1 end_log_pos 6826 Intvar
SET INSERT_ID=27/*!*/;
# at 6826
#120414 13:26:22 server id 1 end_log_pos 7060 Query thread_id=283 exec_time=0 error_code=0
SET TIMESTAMP=1334381182/*!*/;
INSERT INTO pre_common_credit_rule_log SET `uid`=124151 , `rid`=’15’ , `fid`=0 , `total`=1 , `cyclenum`=1 , `dateline`=1334381182 , `extcredits1`=5 , `extcredits3`=0
/*!*/;
# at 7060
#120414 13:26:22 server id 1 end_log_pos 7219 Query thread_id=283 exec_time=0 error_code=0
SET TIMESTAMP=1334381182/*!*/;
UPDATE pre_common_member_count SET `extcredits1`=`extcredits1`+’5′ WHERE uid IN (‘124151’)
/*!*/;
# at 7219
#120414 13:26:22 server id 1 end_log_pos 7348 Query thread_id=283 exec_time=0 error_code=0
SET TIMESTAMP=1334381182/*!*/;
UPDATE pre_common_member SET `credits`=5 WHERE `uid`=124151
/*!*/;
# at 7348
#120414 13:26:22 server id 1 end_log_pos 7496 Query thread_id=283 exec_time=0 error_code=0
SET TIMESTAMP=1334381182/*!*/;
UPDATE pre_common_stat SET `register`=`register`+1 WHERE `daytime` = ‘20120414’
/*!*/;

Read More

dx2.5中从core剥离的get_title_page在哪里~

最近改造一个老版本的插件

 

列表页显示空白,开启debug之后报错如下

Call to undefined function get_title_page() in /root/www/XXXXX/source/plugin/weitie/weitie_forumdisplay.inc.php on line 128

 

查了dz的wiki,,get_title_page这个函数还是x2老版本的core包里面的函数

/**
 * 返回带第几页的title
 * @global  $_G
 * @param string $navtitle 源标题
 * @param int $page 页码
 * @return string
 */
function get_title_page($navtitle, $page){
	if($page > 1) {
    ......
}

 

x2.5的时候对core进行了很大的精简,

所以现在需要使用get_title_page,他已经被转移到helper去了

调用方法

helper_seo::get_title_page

即变为了helper_seo的静态方法,直接调用即可.

 

 

Read More