Archive for July, 2007

备份mysql,生成sql,csv,xls,xml文件的PHP程序

Tuesday, July 31st, 2007

本程序的功能主要有备份mysql数据库,生成SQL文件,XML文件,CSV文件,XLS文件,将此代码复制粘贴到一个PHP文件中,生成的备份文件都在该同级目录下。
代码如下:
//mysqldb.php
//manage mysql database and table , backup data and create xml and csv file
//Rossy.cn@gmail.com
//2007-07-31 18:34:25

//messages for no table exist in database or no field exist in the table
if (isset($_GET['Tip']) && (!empty($_GET['Tip']))) {
$Tip = trim($_GET['Tip']);
if ($Tip == "t") {
echo "No table in this database
";
} elseif ($Tip == "d") {
echo "No data in this table
";
}
}
error_reporting(0);
define("CURFILE","mysqldb.php"); //current file name
define("Mysql_Host","localhost"); //mysql host name
define("Mysql_User","username"); //mysql user
define("Mysql_Pwd","password"); //mysql password
$link = mysql_connect(Mysql_Host,Mysql_User,Mysql_Pwd); //connect database

//select database
if (isset($_GET['db']) && (!empty($_GET['db']))) {
$db = trim($_GET['db']);
//select table
if (isset($_GET['table']) && (!empty($_GET['table']))) {
$table = trim($_GET['table']);
mysql_select_db($db,$link) or die ('Can\'t use foo : ' . mysql_error());
$query = "Select * FROM `$table` Where 1 = 1";
$result = mysql_query($query) or die ('Query Failed : ' . mysql_error());
if (mysql_num_rows($result)<=0) header("Location:".$file."?Tip=d&db=".$db); //return when table has no field

if (isset($_GET['type']) && (trim($_GET['type'])=="xml")) {
//create xml file
echo "databases –> ".$db." –> ".$table."
";
$filestr = "<"."?xml version=\"1.0\" encoding=\"utf-8\"?".">\n";
$filestr .="<".$table."s>\n";
while ($row = mysql_fetch_array($result)){
$filestr .= "<".$table.">\n";
$fields = mysql_list_fields($db,$table,$link);
$j = 0;
while ($j $num_fields = mysql_field_name($fields,$j);
$filestr .= "<".$num_fields.">";
$filestr .= $row[$j];
$filestr .= "\n";
$j++;
}
$filestr .= "\n";
}
$filestr .= "";
$xmlfilename = $table.".xml";
$fp = fopen("$xmlfilename","w");
fwrite($fp,$filestr);
fclose($fp);
echo "
create xml successfully! file name is ".$xmlfilename;
} elseif (isset($_GET['type']) && (trim($_GET['type'])=="view")) {
//view table's structure
echo "databases –> ".$db." –> ".$table."
";
echo "
This is the fields in this table
";
while ($row = mysql_fetch_array($result)){
$fields = mysql_list_fields($db,$table,$link);
$k = 0;
while ($k $name_fields = mysql_field_name($fields,$k);
$type_fields = mysql_field_type($fields,$k);
$lens_fields = mysql_field_len($fields,$k);
$flag_fields = mysql_field_flags($fields,$k);
echo "".$name_fields." (".$type_fields."|".$lens_fields.") ".$flag_fields."
";
$k++;
}
}
} elseif (isset($_GET['type']) && (trim($_GET['type'])=="bk")) {
//backup data into sql file
echo "databases –> ".$db." –> ".$table."
";
$bkfilename = $table.date("Y-m-d-H-i-s").".sql";
$query = "Select * INTO OUTFILE '".$_SERVER['DOCUMENT_ROOT']."/test/".$bkfilename."' FROM $table";
$result = mysql_query($query) or die("backup data failed :".mysql_error());
echo "
backup successfully . file name is :".$bkfilename."
";
} elseif (isset($_GET['type']) && (trim($_GET['type'])=="view")) {
echo "databases –> ".$db." –> ".$table."
";
echo "
This is the fields in this table
";
while ($row = mysql_fetch_array($result)){
$fields = mysql_list_fields($db,$table,$link);
$n = 0;
while ($n $name_fields = mysql_field_name($fields,$n);
$type_fields = mysql_field_type($fields,$n);
$lens_fields = mysql_field_len($fields,$n);
$flag_fields = mysql_field_flags($fields,$n);
echo "".$name_fields." (".$type_fields."|".$lens_fields.") ".$flag_fields."
";
$n++;
}
}
} elseif (isset($_GET['type']) && (trim($_GET['type'])=="csv")) {
//create csv file
$csvfilename = $table.date("Y-m-d-H-i-s").".csv";
header( "Content-type: application/vnd.ms-excel;charset=utf-8" );
header( "Content-Disposition: csv; filename=".$csvfilename );
$fields = mysql_list_fields($db,$table,$link);
$h = 0;
for ($h = 0; $h < mysql_num_fields($fields); $h++) {
echo '"'.mysql_field_name($result,$h).'"';
if (($h+1)==mysql_num_fields($fields)) break;
else echo ",";
}
echo "\015\012";
while ($row = mysql_fetch_array($result)){
$i = 0;
while ($i echo '"'.$row[$i].'"';
//echo '"'.iconv("BIG5","UTF-8",$row[$i]).'"';
if (($i+1)==mysql_num_fields($fields)) break;
else echo ",";
$i++;
}
echo "\015\012";
}
} elseif (isset($_GET['type']) && (trim($_GET['type'])=="xls")) {
//create xls file
$xlsfilename = $table.date("Y-m-d-H-i-s").".xls";
header( "Content-type: application/vnd.ms-excel;charset=utf-8" );
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Type: application/force-download");
header("Content-Type: application/octet-stream");
header("Content-Type: application/download");
header( "Content-Disposition: xls; filename=".$xlsfilename );
$fields = mysql_list_fields($db,$table,$link);
$h = 0;
echo "

";
for ($h = 0; $h < mysql_num_fields($fields); $h++) {
echo "

";
}
echo "

";
while ($row = mysql_fetch_array($result)){
$i = 0;
echo "

";
while ($i echo "

";
$i++;
}
echo "

";
}
echo "

".mysql_field_name($result,$h)."
".$row[$i]."

";
}
} else {
//list tables in select database
$lists=mysql_list_tables($db,$link);
$m=0;
if (mysql_num_rows($lists) == 0) header("Location:".$file."?Tip=t");
echo "databases –> ".$db."
";
while($m $tb_name=mysql_tablename($lists,$m);
$fields = mysql_list_fields($db,$tb_name,$link);
$field_num = mysql_num_fields($fields);
echo "".($m+1)." ".$tb_name."(".$field_num.") "."(VIEW) || "."(BACKUP) || "."(XML) || "."(CSV) || "."(XLS)
";
$m++;
}
}
} else {
//list database
$db_list = mysql_list_dbs($link);
while ($row = mysql_fetch_object($db_list)) {
$result = mysql_list_tables($row->Database,$link);
$table_num = mysql_num_rows($result);
echo "Database."\">".$row->Database. "(".$table_num.")
\n";
}
}
?>

网页使用EMBED媒体播放音乐大全

Friday, July 27th, 2007

由于需要,今天特制作了一个自动播放,点击停止播放或播放音乐的网页,所以使用了EMBED元素。
将以下代码COPY过去就可以点击STOP或者PLAY测试了。实现的方法也很简单,设置一个空层,点击播放的时候载入相应的自动播放音乐文件的HTML代码,而停止则重新载入不自动播放音乐的HTML代码。
<div id="bgarea" style="display:none;"></div>
<br>
<a href="javascript:void(0);" onClick="javascript:StopSound();">STOP</a>&nbsp;&nbsp;&nbsp;<a href="javascript:void(0);" onClick="javascript:PlaySound();">Play</a>
<br>
<script language="javascript" type="text/javascript">
<!–//
function StopSound() {
 var a = document.getElementById(’bgarea’);
 a.innerHTML = "<embed id=\"bgsound\" autostart=\"false\" hidden=\"true\" src=\"dazkj.mp3\" loop=\"true\" width=\"300px\" height=\"150px\"></embed>";
}
function PlaySound() {
 var o = document.getElementById(’bgarea’);
 o.innerHTML = "<embed id=\"bgsound\" autostart=\"true\" hidden=\"true\" src=\"dazkj.mp3\" loop=\"true\" width=\"300px\" height=\"150px\"></embed>";
}
window.onload=PlaySound;
//–>
</script>
但这个只是简单的带有停止和播放功能的播放,所以去GOGO了一下,终于搜索到了EMBED元素的一些高级参数,可以暂停,停止,播放音乐文件,但只支持IE系列浏览器,不支持FireFox和Opera浏览器。

效果如下:

 


Sound card enabled:
State:
Position:
Filename:

代码如下:

<HTML>
<HEAD>
<TITLE>Embedding Sound in Web Pages, Part I: Audio Control Example - Doc JavaScript</title>
</HEAD>
<BODY BGCOLOR="#ffffff">
</P>
<H2>Audio Control Example</H2>
<P>Let’s look at an example that demonstrates many of the LiveAudio and ActiveMovie methods. The following form lets you set several properties of the LiveAudio plug-in and ActiveMovie Control:</P>
<SCRIPT LANGUAGE="JavaScript">
<!–
var NSsound = navigator.plugins && navigator.plugins["LiveAudio"];
var IEsound = navigator.plugins && document.all;
var audioEnabled = NSsound || IEsound;

if (!audioEnabled) alert("Your browser cannot play sound files.");
if (!navigator.javaEnabled()) alert("Your browser is not Java-enabled. Please edit preferences.");

onload = init;
timerID = null;

function init() {
  if (!navigator.javaEnabled()) return;
  if (!audioEnabled) return;
  document.display.soundcard.value = (IEsound) ? document.audiopanel.isSoundCardEnabled() : "not supported";
  document.display.filename.value = (IEsound) ?  document.audiopanel.fileName : "not supported";
  endTime = (IEsound) ? document.audiopanel.selectionEnd : "not supported"; // global variable
  document.display.position.value = (IEsound) ? Math.floor(document.audiopanel.currentPosition) : "not supported";
  state();
}

function showPosition() {
  if (!navigator.javaEnabled()) return;
  if (!audioEnabled) return;
  document.display.position.value = (IEsound) ? Math.floor(document.audiopanel.currentPosition) : "not supported";
  setTimeout("showPosition()", 1000);
}

function playIt() {
  if (!navigator.javaEnabled()) return;
  if (!audioEnabled) return;
  if (IEsound) document.audiopanel.play()
  else if (NSsound) document.audiopanel.play(true);
  state();
  timerID = setTimeout("showPosition()", 1000);
}

function stopIt() {
  if (!navigator.javaEnabled()) return;
  if (!audioEnabled) return;
  document.audiopanel.stop();
  state();
  clearInterval(timerID);
}

function pauseIt() {
  if (!navigator.javaEnabled()) return;
  if (!audioEnabled) return;
  document.audiopanel.pause();
  state();
  clearInterval(timerID);
}

function state() {
  if (!navigator.javaEnabled()) return;
  var field = document.display.state;
  if (IEsound) {
    var cur = document.audiopanel.currentState;
    if (cur == 0) field.value = "stopped";
    if (cur == 1) field.value = "paused";
    if (cur == 2) field.value = "playing";
  }
  else if (NSsound) {
    if (document.audiopanel.IsReady()) field.value = "stopped";
    if (document.audiopanel.IsPlaying()) field.value = "playing";
    if (document.audiopanel.IsPaused()) field.value = "paused";
  }
}

function toggleControls() {
  if (!navigator.javaEnabled()) return;
  if (IEsound)
    document.audiopanel.showControls = !document.audiopanel.showControls;
}

function startAtGivenSec(sec) {
  if (!navigator.javaEnabled()) return;
  if (IEsound)
    document.audiopanel.selectionStart = sec
  else if (NSsound)
         document.audiopanel.start_time(sec);
}

function stopAtGivenSec(sec) {
  if (!navigator.javaEnabled()) return;
  if (IEsound)
    document.audiopanel.selectionEnd = sec
  else if (NSsound)
    document.audiopanel.end_time(sec);
}

function stopAtEnd() {
  if (!navigator.javaEnabled()) return;
  if (IEsound)
    document.audiopanel.selectionEnd = endTime
  else if (NSsound)
    document.audiopanel.stop_at_end();
}

function decreaseVolume() {
  if (!navigator.javaEnabled()) return;
  if (IEsound)
    document.audiopanel.volume -= 10
  else if (NSsound)
    document.audiopanel.setvol(parseInt(document.audiopanel.GetVolume() - 10))
}

function increaseVolume() {
  if (!navigator.javaEnabled()) return;
  if (IEsound)
    document.audiopanel.volume += 10
  else if (NSsound)
    document.audiopanel.setvol(document.audiopanel.GetVolume() + 10)
}

function setDefaultVolume() {
  if (!navigator.javaEnabled()) return;
  if (IEsound)
    document.audiopanel.volume = 50
  else if (NSsound)
    document.audiopanel.setvol(50)
}

if (audioEnabled) 
  document.write("<EMBED NAME=’audiopanel’ SRC=’dazkj.mp3′ MASTERSOUND HEIGHT=’60′ WIDTH=’144′ HIDDEN=’false’>")
else
  document.write("Your browser cannot play sound files.");

// –>
</SCRIPT>
<FORM NAME="display">
Sound card enabled: <INPUT TYPE="text" NAME="soundcard" SIZE="14"><BR>
State: <INPUT TYPE="text" NAME="state" SIZE="10"><BR>
Position: <INPUT TYPE="text" NAME="position" SIZE="14"><BR>
Filename: <INPUT TYPE="text" NAME="filename" SIZE="50"><BR>
<INPUT TYPE="button" VALUE="play" onClick="playIt()">
<INPUT TYPE="button" VALUE="Pause" onClick="pauseIt()">
<INPUT TYPE="button" VALUE="Stop" onClick="stopIt()"><BR>
<INPUT TYPE="button" VALUE="Toggle Controls" onClick="toggleControls()"><BR>
<INPUT TYPE="button" VALUE="Start @ 10 Second" onClick="startAtGivenSec(10)">
<INPUT TYPE="button" VALUE="Stop @ 30 Second" onClick="stopAtGivenSec(30)"><BR>
<INPUT TYPE="button" VALUE="Start @ 0 Second" onClick="startAtGivenSec(0)">
<INPUT TYPE="button" VALUE="Stop @ End of Track" onClick="stopAtEnd()"><BR>
<INPUT TYPE="button" VALUE="<=====" onClick="decreaseVolume()">
<INPUT TYPE="button" VALUE="==^==" onClick="setDefaultVolume()">
<INPUT TYPE="button" VALUE="=====>" onClick="increaseVolume()"><BR>
</FORM>
<P>The code is shown on the next page. The script is fairly straightforward. Let’s take one function to demonstrate the principles of object referencing:</P>
<P> <PRE><CODE><FONT COLOR="#0000cc">function playIt() {
  if (!audioEnabled) return;
  if (IEsound) </FONT><FONT COLOR="#cc0000">document.audiopanel.play()</FONT><FONT COLOR="#0000cc">
  else if (NSsound) </FONT><FONT COLOR="#009900">document.audiopanel.play(true)</FONT><FONT COLOR="#0000cc">;
  state();
  timerID = setTimeout("showPosition()", 1000);
}</FONT></CODE></PRE> </P>
<P>Explorer plays a sound track by the <CODE><FONT COLOR="#0000cc">play()</FONT></CODE> method, while Navigator does it with the <CODE><FONT COLOR="#0000cc">play()</FONT></CODE> one. Differences stem from the fact that Navigator uses the LiveAudio plug-in, while Explorer uses the ActiveMovie Control, as explained earlier in this column. On both browsers, an object is referenced as <CODE><FONT COLOR="#0000cc">document.audiopanel</FONT></CODE>, where <CODE><FONT COLOR="#0000cc">audiopanel</FONT></CODE> is the value of the <CODE><FONT COLOR="#0000cc">&lt;EMBED&gt;</FONT></CODE> tag’s <CODE><FONT COLOR="#0000cc">NAME</FONT></CODE> attribute. The function <CODE><FONT COLOR="#0000cc">state()</FONT></CODE> prints the state of the sound control, and the last line of the <CODE><FONT COLOR="#0000cc">playIt()</FONT></CODE> function invokes the <CODE><FONT COLOR="#0000cc">setInterval()</FONT></CODE> function to update the position of the track every 1000 ms.</P>
<P>Notice that the Explorer’ ActiveMovie Control supports several features that Navigator does not. For example, Explorer lets you read the current playing position along the track, the audio file name, and if the sound card is enabled. Compare the feature table of LiveAudio with that of ActiveMovie Control, and you will find many more such features.</P>
</BODY>
</HTML>

相关链接:http://www.webreference.com/js/column20/liveaudioexample.html

其它EMBED参数如下:

例:<EMBED src="音乐地址" autostart="true" loop="true" width="180" height="120">

SRC:设定关联的文档,可以是相对路径或绝对路径。例:src="xt.rm"
autostart 是否在音乐档下载完之后就自动播放。"true" 是,"false" 否
loop 是否自动反复播放。LOOP=2 表示重复两次,true 是, false 否。  
ALIGN 设定控制画面和旁边文字的对齐方式,其值可以是 top、bottom、center、baseline、 left、right、texttop、middle、absmiddle、absbottom 。  
ALT  程序不能正确运行时用来替代显示的文字.
CONTROLS设定控制面板的外观。预设值是 console。
   console 一般正常面板
   controlpanel 精简面板 
   smallconsole 更小的面板   
   playbutton 只显示播放按钮   
   pausecutton 只显示暂停按钮   
   stopbutton 只显示停止按钮   
   volumelever 只显示音量调节按钮
   imagewindow 只显示播放器屏幕
   statusbar 只显示相关信息 例如 传速 播放时间
CLASS:给该标记指定一个事先定义好的样式类。
   CODE:class文件名,嵌入的是一个Java Applet.
   CODEBASE:指定包含文档的目录的路径.
HIDDEN:是否完全隐藏控制画面,true 为是,no 为否  
HEIGHT:显示该文档的区域的高度.
WIDTH:显示该文档的区域的宽度.
HSPACE:显示该文档时的水平间距.
VSPACE:显示该文档时的垂直间距.
ID:给该元素定义一个在文档中唯一的标识。有效标识以字母开头,可以在中间使用下划线。
NAME:指定程序的名称.
STYLE:指定该元素的样式。
title:定义提示信息,提示信息文字在响应onmouseover事件时显示出来。
UNITS:指定高宽值的单位,可以是像素(px)或ems (em).

PHP数组重复值相加计算

Thursday, July 26th, 2007

目的:计算各种不同的价格单位的价格总和。
数据:
do {
$Price[] = $rs['Price'];
}
数组形式:$Price = array("212|RMB","152|RMB","170|RMB","321|RMB","140|USD","210|USD");//价格|符号
要求达到的效果:RMB:855 USD:350
由于对数组的操作实践不够,所以查PHP手册上的数组函数,试着去解决问题,最终还是在单独的一个测试页面里成功做出来了。代码如下:
$Price = array("212|RMB","152|RMB","170|RMB","321|RMB","140|USD","210|USD");//价格|符号
foreach ($Priceb as $a) {
$b =explode("|",$a);
$sym[] = $b[1];//符号
$pri[] = $b[0];//价格
}
$Pricet = array_keys(array_count_values($sym));//符号总数
for ($i=0;$i for ($j=0;$j if ($Pricet[$i]==$sym[$j]) $Price[$i][] = $pri[$j];
}
echo $Pricet[$i].":".array_sum($Price[$i])."&nbsp;&nbsp;";//符号:价格
}
但是发觉这样太过复杂,而且在实际操作中(从数据库读取数组出来),会出现Cannot use string offset as an array in E:\DATA\Report.php on line 119;这个错误提示,查了相关资料都不能解决问题,只好上CSDN上发帖求助,最终得到了一个理想的结果,由wasuka(萝莉控)写出的答案:
$Pricea = array("212|RMB","152|RMB","170|RMB","321|RMB","140|USD","210|USD");//价格|符号
foreach($Pricea as $v)
{
$tatol = explode("|", $v);
$a[$tatol[1]] += $tatol[0];
}
foreach($a as $key=>$val){
echo $key.":".$val."&nbsp;&nbsp;"; //符号:价格总数
}
佩服!原来数组的用法是如此之多,如此之妙,如此之简单。
CSDN相关帖子:http://community.csdn.net/Expert/topic/5674/5674007.xml

PHP程序漏洞产生的原因和防范方法

Thursday, July 26th, 2007

滥用include

  1.漏洞原因:

  Include是编写PHP网站中最常用的函数,并且支持相对路径。有很多PHP脚本直接把某输入变量作为Include的参数,造成任意引用脚本、绝对路径泄露等漏洞。看以下代码:


$includepage=$_GET["includepage"];
include($includepage);

  很明显,我们只需要提交不同的Includepage变量就可以获得想要的页面。如果提交一个不存在的页面,就可以使PHP脚本发生错误而泄露实际绝对路径(这个问题的解决办法在下面的文章有说明)。

  2.漏洞解决:

  这个漏洞的解决很简单,就是先判断页面是否存在再进行Include。或者更严格地,使用数组对可Include的文件作出规定。看以下代码:

$pagelist=array("test1.php","test2.php","test3.php"); //这里规定可进行include的文件
if(isset($_GET["includepage"])) //判断是否有$includepage
{
 $includepage=$_GET["includepage"];
 foreach($pagelist as $prepage)
 {
  if($includepage==$prepage) //检查文件是否在允许列表中
  {
   include($prepage);
   $checkfind=true;
   break;
  }
 }
 if($checkfind==true){ unset($checkfind); }
 else{ die("无效引用页!"); }
}
  这样就可以很好地解决问题了。

  小提示:有此问题的函数还有:require(),require_once(),include_once(),readfile()等,在编写的时候也要注意。

未对输入变量进行过滤

  1.漏洞原因:

  这个漏洞早在ASP中出现过,当时造成的注入漏洞不计其数。但由于PHP在当时的影响力较小,所以没有太多的人能够注意这点。对于PHP来说,这个漏洞的影响性比ASP更大,因为有比较多的PHP脚本使用到文本型数据库。当然也存在SQL语句的注入问题。举个比较经典的例子,首先是数据库的:

$id=$_GET["id"];

$query="Select * FROM my_table where id='".$id."'"; //很经典的SQL注入漏洞
$result=mysql_query($query);
  这里很明显我们可以用注入来获得数据库的其它内容了。这里就不再详细叙述,和ASP注入一样的,大家可以看看以前的黑防。然后我们看文本数据库的问题:

$text1=$_POST["text1"];
$text2=$_POST["text2"];
$text3=$_POST["text3"];

$fd=fopen("test.php","a");
fwrite($fd,"\r\n$text1&line;$text2&line;$text3");
fclose($fd);
  文本的漏洞可以说是更加严重。倘若我们的提交的变量中插入一段很小的PHP代码,就可以另这个文本数据库test.php变成PHP后门。甚至插入上传代码,让我们可以上传一个完善的PHP后门。接着提升权限,服务器就是你的了。

  2.漏洞解决:

  这个漏洞的解决方法其实很简单,就是严格对全部提交的变量进行过滤。对一些敏感的字符进行替换。我们可以借助PHP提供的htmlspecialchars()函数来替换HTML的内容。这里给出一段例子:

//构造过滤函数
function flt_tags($text)
{
 $badwords=array("操你妈","fuck"); //词汇过滤列表
 $text=rtrim($text);
 foreach($badwords as $badword) //这里进行词汇的过滤
 {
  if(stristr($text,$badword)==true){ die("错误:你提交的内容含有敏感字眼,请不要提交敏感内容。"); }
 }
 $text=htmlspecialchars($text); //HTML替换
 //这两行把回车替换为

 $text=str_replace("\r"," ",$text);
 $text=str_replace("\n","",$text);
 $text=str_replace("&line;","│",$text); //文本数据库分隔符"&line;"替换为全角的"│"
 $text=preg_replace("/\s{ 2 }/"," ",$text); //空格替换
 $text=preg_replace("/\t/"," ",$text); //还是空格替换
 if(get_magic_quotes_gpc()){ $text=stripslashes($text); } //如果magic_quotes开启,则进行\'的替换
 return $text;
}

$text1=$_POST["text1"];
$text2=$_POST["text2"];
$text3=$_POST["text3"];

//过滤全部输入
$text1=flt_tags($text1);
$text2=flt_tags($text2);
$text3=flt_tags($text3);

$fd=fopen("test.php","a");
fwrite($fd,"\r\n$text1&line;$text2&line;$text3");
fclose($fd);
  经过一番替换和过滤后,你就可以安全地把数据写入文本或数据库了。

管理员判断不完全

  1.漏洞原因:

  我们用PHP写脚本,通常要涉及管理员的权限问题。而一些脚本仅仅对管理员权限作出"是"判断,而往往忽略了"否"判断。在PHP配置文件中register_globals打开的情况下(4.2.0以后版本默认关闭,但有不少人为了方便而打开它,这是极度危险的行为),就会出现提交变量冒充管理员的情况。我们看一下的例子代码:

$cookiesign="admincookiesign"; //判断是否Admin的cookie变量
$adminsign=$_COOKIE["sign"]; //获取用户的cookie变量

if($adminsign==$cookiesign)
{
 $admin=true;
}

if($admin){ echo "现在是管理员状态。"; }
  看上去好像很安全的样子,呵呵。现在我们假设PHP配置文件中register_globals为打开状态。我们提交这样一个地址“test.php?admin=true”,结果看到了吗?我们虽然没有正确的Cookie,但由于register_globals为打开状态,使得我们提交的admin变量自动注册为true。而且脚本缺少“否”判断,就使得我们顺利地通过admin=true取得管理员的权限了。这个问题存在于大部分网站和论坛当中。

  2.漏洞解决:

  解决这个问题,我们只需要在脚本中加入对管理员的“否”判断即可。我们仍然假设PHP配置文件中register_globals为打开状态。看一下的代码:

$cookiesign="admincookiesign"; //判断是否Admin的cookie变量
$adminsign=$_COOKIE["sign"]; //获取用户的cookie变量

if($adminsign==$cookiesign)
{
 $admin=true;
}
else
{
 $admin=false;
}
if($admin){ echo "现在是管理员状态。"; }
  这样,就算攻击者在没有正确Cookie的情况下提交了admin=true的变量,脚本在以后的判断中也会把$admin设置为False。这样就解决了部分的问题。但由于$admin是变量,倘若在以后的其他脚本引用中出现了漏洞使得$admin被重新赋值就会引发新的危机。因此,我们应该使用常量来存放管理员权限的判定。使用Define()语句定义一个admin常量来记录管理员权限,在此以后若配重新赋值就会出错,达到保护的目的。看以下代码:

$cookiesign="admincookiesign"; //判断是否Admin的cookie变量
$adminsign=$_COOKIE["sign"]; //获取用户的cookie变量

if($adminsign==$cookiesign)
{
 define(admin,true);
}
else
{
 define(admin,false);
}
if(admin){ echo "现在是管理员状态。"; }
  值得注意的是,我们使用了Define语句,所以在调用Admin常量时前面不要习惯性的加变量符号$,而应该使用Admin和!admin。

文本数据库暴露

  1.漏洞原因:

  前面已经说过,由于文本数据库具有很大的灵活性,不需要任何外部支持。加上PHP对文件的处理能力十分强,因此文本数据库在PHP脚本中的应用甚广。甚至有几个很好的论坛程序就是使用文本数据库的。但有得必有失,文本数据库的安全性也是比其他数据库要低的。

  2.漏洞解决:

  文本数据库作为一个普通的文件,它可以被下载,就像MDB一样。所以我们要用保护MDB的办法来保护文本数据库。把文本数据库的后缀名改为.PHP。并在数据库的第一行加入。这样文本数据库就会作为一个PHP文件,并且在第一行退出执行。也就是返回一个空页面,从而达到保护文本数据库的目的。

错误路径泄露

  1.漏洞原因:

  PHP遇到错误时,就会给出出错脚本的位置、行数和原因,例如:

Notice: Use of undefined constant test - assumed 'test' in D:\interpub\bigfly\test.php on line 3
  有很多人说,这并没有什么大不了。但泄露了实际路径的后果是不堪设想的,对于某些入侵者,这个信息可是非常重要,而事实上现在有很多的服务器都存在这个问题。

  有些网管干脆把PHP配置文件中的display_errors设置为Off来解决,但本人认为这个方法过于消极。有些时候,我们的确需要PHP返回错误的信息以便调试。而且在出错时也可能需要给用户一个交待,甚至导航到另一页面。

  2.漏洞解决:

  PHP从4.1.0开始提供了自定义错误处理句柄的功能函数set_error_handler(),但很少数脚本编写者知道。在众多的PHP论坛中,我只看见很少一部分对此情况进行了处理。set_error_handler的使用方法如下:

string set_error_handler ( callback error_handler [, int error_types])
  现在我们就用自定义的错误处理把实际路径过滤掉。

//admin为管理员的身份判定,true为管理员。
//自定义的错误处理函数一定要有这4个输入变量$errno,$errstr,$errfile,$errline,否则无效。
function my_error_handler($errno,$errstr,$errfile,$errline)
{
//如果不是管理员就过滤实际路径
if(!admin)
{
 $errfile=str_replace(getcwd(),"",$errfile);
 $errstr=str_replace(getcwd(),"",$errstr);
}

switch($errno)
{
 case E_ERROR:
  echo "ERROR: [ID $errno] $errstr (Line: $errline of $errfile)
  \n";
  echo "程序已经停止运行,请联系管理员。";
   //遇到Error级错误时退出脚本
   exit;
  break;
 case E_WARNING:
  echo "WARNING: [ID $errno] $errstr (Line: $errline of $errfile)
  \n";
  break;
 default:
  //不显示Notice级的错误
  break;
}
}

//把错误处理设置为my_error_handler函数
set_error_handler("my_error_handler");

  这样,就可以很好地解决安全和调试方便的矛盾了。而且你还可以花点心思,使错误提示更加美观以配合网站的风格。不过注意两点是:

  (1)E_ERROR、E_PARSE、E_CORE_ERROR、E_CORE_WARNING、E_COMPILE_ERROR、E_COMPILE_WARNING是不会被这个句柄处理的,也就是会用最原始的方式显示出来。不过出现这些错误都是编译或PHP内核出错,在通常情况下不会发生。

  (2)使用set_error_handler()后,error_reporting ()将会失效。也就是所有的错误(除上述的错误)都会交给自定义的函数处理。
其它有关于set_error_handler()的信息,大家可以参考PHP的官方手册。

POST漏洞

  1.漏洞原因:

  前面已经说过,依靠register_globals来注册变量是个不好的习惯。在一些留言本和论坛程序中,更要严格检查获得页面的方式和提交的时间间隔。以防止灌水式发帖和外部提交。我们看一下以下某留言本程序的代码:


$text1=flt_tags($text1);
$text2=flt_tags($text2);
$text3=flt_tags($text3);

$fd=fopen("data.php","a");
fwrite($fd,"\r\n$text1&line;$text2&line;$text3");
fclose($fd);

  很明显的,如果我们提交网址”post.php?text1=testhaha&text2=testhaha&text3=testhaha”。数据就会被正常写入文件中。此程序并没有检测变量的来源和浏览器获得页面的方式。如果我们向这个页面重复多次提交,就会起到洪水的作用。现在也有一些软件利用这个漏洞来在论坛或留言本上发广告,这是可耻的行为(我朋友的留言本就在1星期内被灌了10多页,无奈)。

  2.漏洞解决:

  在进行数据处理和保存前,首先判断浏览器的获得页面方式。使用$_SERVER["REQUEST_METHOD"]变量来获得浏览器的获得页面方式。检查其是否为”POST”。在脚本中使用session来记录用户是否通过正常途径(即填写提交内容的页面)来提交数据。或使用$_SERVER["HTTP_REFERER"]来检测,但不推荐这样做。因为部分浏览器没有设置REFERER,有部分防火墙也会屏蔽REFERER。另外,我们也要对提交内容检查,看数据库中是否有重复内容。以留言本为例,使用Session进行判定:
填写浏览内容的页面中,我们在最前端加上:

$_SESSION["allowgbookpost"]=time(); //登记填写时的时间
  在接受留言数据并保存的页面中我们在进行数据处理前我们也用Session进行以下处理:

if(strtoupper($_SERVER["REQUEST_METHOD"])!=”POST”){ die("错误:请勿在外部提交。"); } //检查页面获得方法是否为POST
if(!isset($_SESSION["allowgbookpost"]) or (time()-$_SESSION["allowgbookpost"] < 10)){ die("错误:请勿在外部提交。"); } //检查留言填写时的时间
if(isset($_SESSION["gbookposttime"]) and (time()-$_SESSION["gbookposttime"] < 120)){ die("错误:两次提交留言的间隔不得少于 2 分钟。"); } //检查留言间隔

unset($_SESSION["allowgbookpost"]); //注销allowgbookpost变量以防止一次进入填写页面多次进行提交
$_SESSION["gbookposttime"]=time(); //登记发送留言的时间,防止灌水或恶意攻击

数据处理及保存

  经过这样重重审查,你的程序就安全很多了。

学习javascript所必须要知道的一些小技巧

Tuesday, July 24th, 2007

每一项都是js中的小技巧,但十分的实用!
1.document.write(""); 输出语句
2.JS中的注释为//
3.传统的HTML文档顺序是:document->html->(head,body)
4.一个浏览器窗口中的DOM顺序是:window->(navigator,screen,history,location,document)
5.得到表单中元素的名称和值:document.getElementById("表单中元素的ID号").name(或value)
6.一个小写转大写的JS: document.getElementById("output").value = document.getElementById("input").value.toUpperCase();
7.JS中的值类型:String,Number,Boolean,Null,Object,Function
8.JS中的字符型转换成数值型:parseInt(),parseFloat()
9.JS中的数字转换成字符型:(""+变量)
10.JS中的取字符串长度是:(length)
11.JS中的字符与字符相连接使用+号.
12.JS中的比较操作符有:==等于,!=不等于,>,>=,<.<=
13.JS中声明变量使用:var来进行声明
14.JS中的判断语句结构:if(condition){}else{}
15.JS中的循环结构:for([initial expression];[condition];[upadte expression]) {inside loop}
16.循环中止的命令是:break
17.JS中的函数定义:function functionName([parameter],...){statement[s]}
18.当文件中出现多个form表单时.可以用document.forms[0],document.forms[1]来代替.
19.窗口:打开窗口window.open(), 关闭一个窗口:window.close(), 窗口本身:self
20.状态栏的设置:window.status="字符";
21.弹出提示信息:window.alert("字符");
22.弹出确认框:window.confirm();
23.弹出输入提示框:window.prompt();
24.指定当前显示链接的位置:window.location.href="URL"
25.取出窗体中的所有表单的数量:document.forms.length
26.关闭文档的输出流:document.close();
27.字符串追加连接符:+=
28.创建一个文档元素:document.createElement(),document.createTextNode()
29.得到元素的方法:document.getElementById()
30.设置表单中所有文本型的成员的值为空:
var form = window.document.forms[0]
for (var i = 0; i
if (form.elements.type == "text"){
form.elements.value = "";
}
}
31.复选按钮在JS中判断是否选中:document.forms[0].checkThis.checked (checked属性代表为是否选中返回TRUE或FALSE)
32.单选按钮组(单选按钮的名称必须相同):取单选按钮组的长度document.forms[0].groupName.length
33.单选按钮组判断是否被选中也是用checked.
34.下拉列表框的值:document.forms[0].selectName.options[n].value (n有时用下拉列表框名称加上.selectedIndex来确定被选中的值)
35.字符串的定义:var myString = new String("This is lightsword");
36.字符串转成大写:string.toUpperCase(); 字符串转成小写:string.toLowerCase();
37.返回字符串2在字符串1中出现的位置:String1.indexOf("String2")!=-1则说明没找到.
38.取字符串中指定位置的一个字符:StringA.charAt(9);
39.取出字符串中指定起点和终点的子字符串:stringA.substring(2,6);
40.数学函数:Math.PI(返回圆周率),Math.SQRT2(返回开方),Math.max(value1,value2)返回两个数中的最在值,Math.pow(value1,10)返回value1的十次方,Math.round(value1)四舍五入函数,Math.floor(Math.random()*(n+1))返回随机数
41.定义日期型变量:var today = new Date();
42.日期函数列表:dateObj.getTime()得到时间,dateObj.getYear()得到年份,dateObj.getFullYear()得到四位的年份,dateObj.getMonth()得到月份,dateObj.getDate()得到日,dateObj.getDay()得到日期几,dateObj.getHours()得到小时,dateObj.getMinutes()得到分,dateObj.getSeconds()得到秒,dateObj.setTime(value)设置时间,dateObj.setYear(val)设置年,dateObj.setMonth(val)设置月,dateObj.setDate(val)设置日,dateObj.setDay(val)设置星期几,dateObj.setHours设置小时,dateObj.setMinutes(val)设置分,dateObj.setSeconds(val)设置秒 [注意:此日期时间从0开始计]
43.FRAME的表示方式: [window.]frames[n].ObjFuncVarName,frames["frameName"].ObjFuncVarName,frameName.ObjFuncVarName
44.parent代表父亲对象,top代表最顶端对象
45.打开子窗口的父窗口为:opener
46.表示当前所属的位置:this
47.当在超链接中调用JS函数时用:(javascript :)来开头后面加函数名
48.在老的浏览器中不执行此JS:
49.引用一个文件式的JS:
50.指定在不支持脚本的浏览器显示的HTML:
51.当超链和onCLICK事件都有时,则老版本的浏览器转向a.html,否则转向b.html.例:dfsadf
52.JS的内建对象有:Array,Boolean,Date,Error,EvalError,Function,Math,Number,Object,RangeError,ReferenceError,RegExp,String,SyntaxError,TypeError,URIError
53.JS中的换行:\n
54.窗口全屏大小:
55.JS中的all代表其下层的全部元素
56.JS中的焦点顺序:document.getElementByid("表单元素").tabIndex = 1
57.innerHTML的值是表单元素的值:如

"how are you"

,则innerHTML的值就是:how are you
58.innerTEXT的值和上面的一样,只不过不会把这种标记显示出来.
59.contentEditable可设置元素是否可被修改,isContentEditable返回是否可修改的状态.
60.isDisabled判断是否为禁止状态.disabled设置禁止状态
61.length取得长度,返回整型数值
62.addBehavior()是一种JS调用的外部函数文件其扩展名为.htc
63.window.focus()使当前的窗口在所有窗口之前.
64.blur()指失去焦点.与FOCUS()相反.
65.select()指元素为选中状态.
66.防止用户对文本框中输入文本:onfocus="this.blur()"
67.取出该元素在页面中出现的数量:document.all.tags("div(或其它HTML标记符)").length
68.JS中分为两种窗体输出:模态和非模态.window.showModaldialog(),window.showModeless()
69.状态栏文字的设置:window.status=’文字’,默认的状态栏文字设置:window.defaultStatus = ’文字.’;
70.添加到收藏夹:external.AddFavorite("http://www.dannyg.com";;,"jaskdlf");
71.JS中遇到脚本错误时不做任何操作:window.onerror = doNothing; 指定错误句柄的语法为:window.onerror = handleError;
72.JS中指定当前打开窗口的父窗口:window.opener,支持opener.opener…的多重继续.
73.JS中的self指的是当前的窗口
74.JS中状态栏显示内容:window.status="内容"
75.JS中的top指的是框架集中最顶层的框架
76.JS中关闭当前的窗口:window.close();
77.JS中提出是否确认的框:if(confirm("Are you sure?")){alert("ok");}else{alert("Not Ok");}
78.JS中的窗口重定向:window.navigate("http://www.sina.com.cn";;);
79.JS中的打印:window.print()
80.JS中的提示输入框:window.prompt("message","defaultReply");
81.JS中的窗口滚动条:window.scroll(x,y)
82.JS中的窗口滚动到位置:window.scrollby
83.JS中设置时间间隔:setInterval("expr",msecDelay)或setInterval(funcRef,msecDelay)或setTimeout
84.JS中的模态显示在IE4+行,在NN中不行:showModalDialog("URL"[,arguments][,features]);
85.JS中的退出之前使用的句柄:function verifyClose(){event.returnValue="we really like you and hope you will stay longer.";}} window.onbeforeunload=verifyClose;
86.当窗体第一次调用时使用的文件句柄:onload()
87.当窗体关闭时调用的文件句柄:onunload()
88.window.location的属性: protocol(http:),hostname(www.example.com),port(80),host(www.example.com:80),pathname("/a/a.html"),hash("#giantGizmo",指跳转到相应的锚记),href(全部的信息)
89.window.location.reload()刷新当前页面.
90.window.history.back()返回上一页,window.history.forward()返回下一页,window.history.go(返回第几页,也可以使用访问过的URL)
91.document.write()不换行的输出,document.writeln()换行输出
92.document.body.noWrap=true;防止链接文字折行.
93.变量名.charAt(第几位),取该变量的第几位的字符.
94."abc".charCodeAt(第几个),返回第几个字符的ASCii码值.
95.字符串连接:string.concat(string2),或用+=进行连接
96.变量.indexOf("字符",起始位置),返回第一个出现的位置(从0开始计算)
97.string.lastIndexOf(searchString[,startIndex])最后一次出现的位置.
98.string.match(regExpression),判断字符是否匹配.
99.string.replace(regExpression,replaceString)替换现有字符串.
100.string.split(分隔符)返回一个数组存储值.
101.string.substr(start[,length])取从第几位到指定长度的字符串.
102.string.toLowerCase()使字符串全部变为小写.
103.string.toUpperCase()使全部字符变为大写.
104.parseInt(string[,radix(代表进制)])强制转换成整型.
105.parseFloat(string[,radix])强制转换成浮点型.
106.isNaN(变量):测试是否为数值型.
107.定义常量的关键字:const,定义变量的关键字:var