PHP实现增删改查以及防SQL注入

来源:互联网 发布:c语言输出ascii码 编辑:程序博客网 时间:2024/06/10 11:32

        最近项目调研时,需要在集成板子上做个配置的网页,板子上装的是linux系统,配置信息在一个SQLite数据库中,经过讨论大家决定用PHP做这个网页。由于项目组没一个会PHP的,所以安排我调研下写个Demo,经过几天的研究终于完成了Demo的调研(调研过程主要参考网络,具体开发就交给月底入职的小弟去做了,哈哈,有个小弟真好),特此记录(根据我调研的顺序展开)。

        项目截图:



        1.搭建环境

        首先当然是搭建环境了,我选择的是phpstudy(下载和安装可参考,完全傻瓜式),编译器选择的是免费的Notepad++(只因为免费而选用,实际效果比记事本好点而已)。至此你可以开发第一个Hello World了。语法可参考。发布也很简单,只要把php文件放到网站目录下就行了(如安装教程中,目录就是D:\WWW)。网站的端口号可以打开phpStudy主界面,点击其他选项菜单,点击myHomePage,就能看到端口号啦。

        2.PHP从SQLite中读取信息

        代码如下:

if ($db = sqlite_open('GateWay.db')) {$sql = "select * from ComInfo";$res = sqlite_unbuffered_query($db, $sql);echo "<table border=1><tr>";echo "<th>comId</th><th>comName</th><th>baud</th><th>parity</th><th>dataBit</th><th>stopBit</th>";echo"</tr>";while($item = sqlite_fetch_array($res, SQLITE_ASSOC)){echo "<tr>";echo "<td>".$item["comId"]."</td>";echo "<td>".$item["comName"]."</td>";echo "<td>".$item["baud"]."</td>";echo "<td>".$item["parity"]."</td>";echo "<td>".$item["dataBit"]."</td>";echo "<td>".$item["stopBit"]."</td></tr>";}echo "</table>";sqlite_close($db);}

        3通过Ajax获得信息

        作为一个网站,现在很少能看到每次提交刷新整个页面的网站了。下面是通过Ajax请求获得数据(这个跟html中类似,这边用的是jQuery中封装的Ajax):在页面上有一个id为fullDataDiv的DIV用来装获取的数据,代码如下:
//js代码var data={ opType:"ShowAllComInfo" };$.post("ComInfoServer.php", data, function (result) {$("#fullDataDiv").html(result);});//ComInfoServer.php页面的代码$opType = $_POST["opType"];switch($opType){case "ShowAllComInfo":{if ($db = sqlite_open('GateWay.db')) {$sql = "select * from ComInfo";$res = sqlite_unbuffered_query($db, $sql);echo "<table border=1><tr>";echo "<th>comId</th><th>comName</th><th>baud</th><th>parity</th><th>dataBit</th><th>stopBit</th>";echo"</tr>";while($item = sqlite_fetch_array($res, SQLITE_ASSOC)){echo "<tr>";echo "<td>".$item["comId"]."</td>";echo "<td>".$item["comName"]."</td>";echo "<td>".$item["baud"]."</td>";echo "<td>".$item["parity"]."</td>";echo "<td>".$item["dataBit"]."</td>";echo "<td>".$item["stopBit"]."</td></tr>";}echo "</table>";sqlite_close($db);} }break;}

        4.新建记录

        接着是新建记录,本质跟Ajax查询类似,代码如下:

//js代码var comName = $('#tbComName').val();var baud = $("select#selBaud option:selected").text();var parity = $("select#selParity option:selected").text();var dataBit = $("select#selDataBit option:selected").text();var stopBit = $("select#selStopBit option:selected").text();var data={opType:"AddComInfo",comName: comName, baud: baud,parity:parity,dataBit:dataBit,stopBit:stopBit};$.post("ComInfoServer.php", data, function (result) {alert("Add Success!");});//ComInfoServer.php页面的代码$comName =$_POST["comName"];$baud = $_POST["baud"];$parity = $_POST["parity"];$dataBit = $_POST["dataBit"];$stopBit = $_POST["stopBit"];if ($db = sqlite_open($dbName)) {$sql= "insert into ComInfo values(null,'".$comName."', '".$baud."','".$parity."',  '".$dataBit."', '".$stopBit."')"; sqlite_query($db, $sql);sqlite_close($db);} 

        5.删除记录

        然后就是删除记录,比新增还简单,只需要传一个ID就行,ID在当前行的第一列(var comInfoid = $(this).parents("tr").find('td:first').text();),代码跟新增类似,就不贴了。

        6.编辑记录

        最后是编辑,为了调研页面跳转,我把编辑放在另一个页面,页面传值直接放在url中,EditComInfoServer.php页面中放了一个隐藏控件保存ComInfoid的值,在页面加载完毕之后根据id向服务端请求完整的数据。代码如下:

//ComInfoMain.php的js代码$(".edit").click(function(){var comInfoid = $(this).parents("tr").find('td:first').text();window.location= "ComInfoServer.php?ComInfoid="+comInfoid;});//EditComInfoServer.php//隐藏控件<div><input type="hidden" id="tbComInfoid" value="<?php echo $_GET['ComInfoid']; ?>"/></div>//js代码$(function () {var URL = "ComInfoHandler.ashx";var data={ComInfoid: $("#tbComInfoid").val(),opType:"EditInit" };$.post(URL, data, function (result) {var info=eval("(" + result + ")");comName =info.comName;baud = info.baud;parity = info.parity;dataBit = info.dataBit;stopBit = info.stopBit;$("#tbComName").val(comName);$("#selBaud  option[value='"+baud+"']").attr("selected", true);$("#selParity  option[value='"+parity+"']").attr("selected", true);$("#selDataBit  option[value='"+dataBit+"']").attr("selected", true);$("#selStopBit  option[value='"+stopBit+"']").attr("selected", true);});});

        7.PHP+Sqlite的防注入以及错误友好提示

        至此初步的增删改查都实现了,但只是实现,根本没考虑安全性。主要有三个方面:如果输入数据库的完整路径,数据库都被下载下来了;或者在comName里精心填入一些字符串就能实现SQL注入;另外出错了,提示也很不友好,直接把程序信息都泄露出来了。

        7.1防止数据库被下载

        对于数据库被下载(这个问题在Access和SQLite中都有),可以不让其直接访问,具体配置是在网站的根目录新建一个文件名为.htaccess的文件(直接新建不了,可以另存为该文件,另外注意的是这个文件与PHP的版本有关,我用的是Apache+PHP5.3),用记事本打开写入内容如下:

<FilesMatch ".db$">Deny from all</FilesMatch>
        其他的设置在最新的版本中已经都是默认设置了,这样,数据库文件就不会被访问下载了。

        7.2防止SQL注入

        对于注入攻击,从两方面下手,前台验证输入的内容(过滤一些注入的关键字),后台再进行二次验证。根据我们实际的业务,我在前台只限制了长度,后台对传入的字符串进行加密之后存到数据库中的,读取的时候再解密。其中解密的几个方法来自这里。这样做法其实对存储有浪费的,经过测试,加密后的字符串长度是原来的两到三倍,图省事我把comName的字段类型改成了text。在实际操作时还遇到了截取字符串乱码的问题,原因是substr在遇到汉字时会遇到编码问题,因此采用mb_substr方法。代码如下:

//新增或更新时$postComName=$_POST["comName"];if(strlen($postComName)>10){$postComName=mb_substr($postComName,0,10,'utf-8');}$comName =passport_encrypt($postComName,$key);//读取时解密$comName=passport_decrypt($item["comName"],$key);

        7.3URL重写

        在注入攻击的问题上还可以通过重写url隐藏网站的技术,当然这不能从本质上防SQL注入,只是提高注入的难度而已。在刚刚的.htaccess加入如下代码:

<IfModule mod_rewrite.c>RewriteEngine onRewriteRule main.html ComInfoMain.phpRewriteRule ComInfoHandler.ashx ComInfoServer.phpRewriteRule ^edit([0-9]+)\.html$ EditComInfoServer.php?ComInfoid=$1   </IfModule>
        这样访问main.html就自动解析为ComInfoMain.php,其中第三个规则是用正则表达式实现,例如edit23.html就解析成EditComInfoServer.php?ComInfoid=23。这个调查了大半天,只因为网上的大多都是以讹传讹(或许是版本的原因吧)。当然了,还有一个原因就是配置文件的苛刻要求。在调查期间删除了一个"看似多余"空格导致Apache启动不起来了,元凶如下:

        这个空格删除了就启动不了Apache,而且没有什么有效的提示,真坑爹。

        7.4错误友好提示

        最后就是错误友好提示了,打开phpStudy主界面,点击其他选项菜单,点击打开配置文件选httpd.conf找到ErrorDocument 404,将其前面的#去除,在后面加上error的页面,本例中设置是ErrorDocument 404 /error.html,这里表示error.html放在网站根目录下。

        至此全部完成,Demo很简单,希望能对刚学PHP的读者有些帮助,欢迎阅读、讨论、转载,转载请保留原文链接。

        Demo下载

0 0
原创粉丝点击