介绍一下GFW的工作原理和封锁技术
GFW是Great Fire Wall的缩写,即“长城防火墙”。这个工程由若干个部分组成,实现不同功能。长城防火墙主要指TG监控和过滤互联网内容的软硬件系统,由服务器和路由器等设备,加上相关的应用程序所构成。
首先,需要强调的是,由于中国网络审查广泛,中国国内含有“不合适”内容的的网站,会受到政府直接的行政干预,被要求自我审查、自我监管,乃至关闭,所以GFW的主要作用在于分析和过滤中国境内外网络的资讯互相访问。
GFW对网络内容的过滤和分析是双向的,GFW不仅针对国内读者访问中国境外的网站进行干扰,也干扰国外读者访问主机在中国大陆的网站。
一 关键字过滤阻断
关键字过滤系统。此系统能够从出口网关收集分析信息,过滤、嗅探指定的关键字。主要针对HTTP的默认端口:80端口,因为HTTP传播的内容是明文的内容,没有经过加密,而GFW是一个IDS(Intrusion detection system)。普通的关键词如果出现在HTTP请求报文的头部(如“Host: www.youtube.com”)时,则会马上伪装成对方向连接两端的计算机发送RST包(reset)干扰两者正常的TCP连接,进而使请求的内容无法继续查看。如果GFW在数据流中发现了特殊的内文关键词(如轮子,达赖等)时,其也会试图打断当前的连接,从而有时会出现网页开启一部分后突然停止的情况。在任何阻断发生后,一般在随后的90秒内同一IP地址均无法浏览对应IP地址相同端口上的内容。
二 IP地址封锁
IP地址封锁是GFW通过路由器来控制的,在通往国外的最后一个网关上加上一条伪造的路由规则,导致通往某些被屏蔽的网站的所有IP数据包无法到达。路由器的正常工作方式是学习别的路由器广播的路由规则,遇到符合已知的IP转发规则的数据包,则按已经规则发送,遇到未知规则IP的数据,则转发到上一级网关。
而GFW对于境外(中国大陆以外)的XX网站会采取独立IP封锁技术。然而部分XX网站使用的是由虚拟主机服务提供商提供的多域名、单(同)IP的主机托管服务,这就会造成了封禁某个IP地址,就会造成所有使用该服务提供商服务的其它使用相同IP地址服务器的网站用户一同遭殃,就算是正常的网站,也不能幸免。其中的内容可能并无不当之处,但也不能在中国大陆正常访问。现在GFW通常会将包含XX信息的网站或网页的URL加入关键字过滤系统,并可以防止民众透过普通海外HTTP代理服务器进行访问。
三 特定端口封锁
GFW会丢弃特定IP地址上特定端口的所有数据包,使该IP地址上服务器的部分功能(如SSH的22、VPN的1723或SSL的443端口等)无法在中国大陆境内正常使用。
在中国移动、中国联通等部分ISP(手机IP段),所有的PPTP类型的VPN都被封锁。
2011年3月起,GFW开始对Google部分服务器的IP地址实施自动封锁(按时间段)某些端口,按时段对www.google.com(用户登录所有Google服务时需此域名加密验证)和mail.google.com的几十个IP地址的443端口实施自动封锁,具体是每10或15分钟可以连通,接着断开,10或15分钟后再连通,再断开,如此循环,令中国大陆用户和Google主机之间的连接出现间歇性中断,使其各项服务出现问题。GFW这样的封锁手法很高明,因为Gmail并非被完全阻断,这令问题看上去好像出自Google本身。这就是你们认为Google抽风的原因。
四 SSL连接阻断
GFW会阻断特定网站的SSL加密连接,方法是通过伪装成对方向连接两端的计算机发送RST包(RESET)干扰两者间正常的TCP连接,进而打断与特定IP地址之间的SSL(HTTPS,443端口)握手(如Gmail、Google文件、Google网上论坛等的SSL加密连接),从而导致SSL连接失败。
当然由于SSL本身的特点,这并不意味着与网站传输的内容可被破译。
五 DNS劫持和污染
GFW主要采用DNS劫持和污染技术,使用Cisco提供的IDS系统来进行域名劫持,防止访问被过滤的网站,2002年Google被封锁期间其域名就被劫持到百度。中国部分ISP也会通过此技术插入广告。
对于含有多个IP地址或经常变更IP地址逃避封锁的域名,GFW通常会使用此方法进行封锁。具体方法是当用户向DNS服务器提交域名请求时,DNS返回虚假(或不解析)的IP地址。
全球一共有13组根域名服务器(Root Server),目前中国大陆有F、I这2个根域DNS镜像,但现在均已因为多次DNS污染外国网络,而被断开与国际互联网的连接。
DNS劫持和污染是针对某些网站的最严重的干扰。
干扰的方式有两种:
一种是通过网络服务提供商(Internet Service Provider)提供的DNS服务器进行DNS欺骗,当人们访问某个网站时,需要要把域名转换为一个IP地址,DNS服务器负责将域名转换为IP地址,中国大陆的ISP接受通信管理局的屏蔽网站的指令后在DNS服务器里加入某些特定域名的虚假记录,当使用此DNS服务器的网络用户访问此特定网站时,DNS服务便给出虚假的IP地址,导致访问网站失败,甚至返回ISP运营商提供的出错页面和广告页面。
另一种是GFW在DNS查询使用的UDP的53端口上根据blacklist进行过滤,遇到通往国外的使用UDP53端口进行查询的DNS请求,就返回一个虚假的IP地址。
Markdown语法介绍
什么是Markdown语法?
Markdown 是一种轻量级标记语言,目标是实现「易读易写」。Coding.net的许多版块都采用了Markdown语法,比如冒泡,讨论,Pull Request等。
标题
在Markdown中,你只需要在文本前面加上# 即可,同理、你还可以增加二级标题、三级标题、四级标题、五级标题和六级标题,总共六级,只需要增加# 即可,标题字号相应降低。例如:
# 一级标题
## 二级标题
### 三级标题
#### 四级标题
##### 五级标题
###### 六级标题
点击预览可以看到效果:
锚点
Coding 会针对每个标题,在解析时都会添加锚点id,如
# 锚点
会被解析成:
<h1 id="user-content-锚点">锚点</h1>
注意我们添加了一个user-content-的前缀所以如果要自己添加跳转链接要使用markdown的形式,且链接要加一个’user-content-‘前缀,如:
[问内链接](#user-content-锚点);
###引用 Markdown 标记区块引用是使用类似 email 中用 > 的引用方式,只需要在整个段落的第一行最前面加上 > :
> Coding.net 为软件开发者提供基于云计算技术的软件开发平台,包括项目管理,代码托管,运行空间和质量控制等等。
效果图如下:
区块引用可以嵌套,只要根据层次加上不同数量的 > :
> 这是第一级引用。
>
> > 这是第二级引用。
>
> 现在回到第一级引用。
效果图如下:
引用的区块内也可以使用其他的 Markdown 语法,包括标题、列表、代码区块等:
> ## 这是一个标题。
>
> 1. 这是第一行列表项。
> 2. 这是第二行列表项。
>
> 给出一些例子代码:
>
> return shell_exec("echo $input | $markdown_script");
效果图如下:
###列表 列表项目标记通常放在最左边,项目标记后面要接一个字符的空格。 无序列表:使用星号、加号或是减号作为列表标记
- Red
- Green
- Blue
效果图如下:
有序列表:使用数字接着一个英文句点
1. Red
2. Green
3. Blue
效果图如下:
如果要在列表项目内放进引用,那 > 就需要缩进:
* Coding.net有以下主要功能:
> 代码托管平台
> 在线运行环境
> 代码质量监控
> 项目管理平台
效果图如下:
代办列表: 表示列表是否勾选状态
- [ ] 不勾选
- [x] 勾选
效果图如下:
代码
只要把你的代码块包裹在 ``` 之间,你就不需要通过无休止的缩进来标记代码块了。 在围栏式代码块中,你可以指定一个可选的语言标识符,然后我们就可以为它启用语法着色了。 举个例子,这样可以为一段 Ruby 代码着色:
```ruby
require 'redcarpet'
markdown = Redcarpet.new("Hello World!")
puts markdown.to_html
```
效果图如下:
强调
在Markdown中,可以使用 * 和 _ 来表示斜体和加粗。
斜体:
*Coding,让开发更简单*
_Coding,让开发更简单_
效果图如下:
加粗:
**Coding,让开发更简单**
__Coding,让开发更简单__
效果图如下:
自动链接
方括号显示说明,圆括号内显示网址, Markdown 会自动把它转成链接,例如:
[超强大的云开发平台Coding](http://coding.net)
效果图如下:
或者也可以直接用< >,将网址或者邮箱地址放在中间,也能将地址直接转成链接:
<support@coding.net>
效果图如下:
表格
在 Markdown 中,可以制作表格,例如:
```
First Header | Second Header | Third Header
------------ | ------------- | ------------
Content Cell | Content Cell | Content Cell
Content Cell | Content Cell | Content Cell
```
效果图如下:
或者也可以让表格两边内容对齐,中间内容居中,例如:
```
First Header | Second Header | Third Header
:----------- | :-----------: | -----------:
Left | Center | Right
Left | Center | Right
```
效果图如下:
分割线
在 Markdown 中,可以制作分割线,例如:
---
效果图如下:
上下标
\^表示上标, _表示下标。如果上下标的内容多于一个字符,要用{}把这些内容括起来当成一个整体。上下标是可以嵌套的,也可以同时使用。 例如:
x^{y^z}=(1+{\rm e}^x)^{-2xy^w}
效果图如下:
图片
Markdown 使用了类似链接的语法来插入图片, 包含两种形式: 内联 和 引用.
内联图片语法如下:
![Alt text](/path/to/img.jpg)
或
![Alt text](/path/to/img.jpg "Optional title")
也就是:
一个感叹号: !
; 紧跟一对方括号, 包含了可选填的图片 alt 属性; 紧跟一对圆括号, 包含了图片的 URL 或者路径, 以及一个可选的用单引号或双引号包裹的 title 属性.
引用图片语法如下:
![Alt text][id]
“id” 是图片引用的名称. 图片引用使用链接定义的相同语法:
[id]: url/to/image "Optional title attribute"
PHP的CURL方法curl_setopt()函数案例介绍(抓取网页,POST数据)
通过curl_setopt()函数可以方便快捷的抓取网页(采集很方便),curl_setopt 是php的一个扩展库
使用条件:需要在php.ini 中配置开启。(PHP 4 >= 4.0.2)
//取消下面的注释
extension=php_curl.dll
在Linux下面,需要重新编译PHP了,编译时,你需要打开编译参数——在configure命令上加上“–with-curl” 参数。
1、 一个抓取网页的简单案例:
- // 创建一个新cURL资源
- $ch = curl_init();
- // 设置URL和相应的选项
- curl_setopt($ch, CURLOPT_URL, "http://www.baidu.com/");
- curl_setopt($ch, CURLOPT_HEADER, false);
- // 抓取URL并把它传递给浏览器
- curl_exec($ch);
- //关闭cURL资源,并且释放系统资源
- curl_close($ch);
2、POST数据案例:
- // 创建一个新cURL资源
- $ch = curl_init();
- $data = 'phone='. urlencode($phone);
- // 设置URL和相应的选项
- curl_setopt($ch, CURLOPT_URL, "http://www.post.com/");
- curl_setopt($ch, CURLOPT_POST, 1);
- curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
- // 抓取URL并把它传递给浏览器
- curl_exec($ch);
- //关闭cURL资源,并且释放系统资源
- curl_close($ch);
3、关于SSL和Cookie
关于SSL也就是HTTPS协议,你只需要把CURLOPT_URL连接中的http://变成https://就可以了。当然,还有一个参数叫CURLOPT_SSL_VERIFYHOST可以设置为验证站点。
关于Cookie,你需要了解下面三个参数:
CURLOPT_COOKIE,在当面的会话中设置一个cookie
CURLOPT_COOKIEJAR,当会话结束的时候保存一个Cookie
CURLOPT_COOKIEFILE,Cookie的文件。
PS:新浪微博登陆API部分截取(部分我增加了点注释,全当参数翻译下。哈哈) 有兴趣的自己研究,自己挪为己用。嘿嘿
- /**
- * Make an HTTP request
- *
- * @return string API results
- * @ignore
- */
- function http($url, $method, $postfields = NULL, $headers = array()) {
- $this->http_info = array();
- $ci = curl_init();
- /* Curl settings */
- curl_setopt($ci, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);//让cURL自己判断使用哪个版本
- curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent);//在HTTP请求中包含一个"User-Agent: "头的字符串。
- curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout);//在发起连接前等待的时间,如果设置为0,则无限等待
- curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout);//设置cURL允许执行的最长秒数
- curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);//返回原生的(Raw)输出
- curl_setopt($ci, CURLOPT_ENCODING, "");//HTTP请求头中"Accept-Encoding: "的值。支持的编码有"identity","deflate"和"gzip"。如果为空字符串"",请求头会发送所有支持的编码类型。
- curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer);//禁用后cURL将终止从服务端进行验证
- curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader'));//第一个是cURL的资源句柄,第二个是输出的header数据
- curl_setopt($ci, CURLOPT_HEADER, FALSE);//启用时会将头文件的信息作为数据流输出
- switch ($method) {
- case 'POST':
- curl_setopt($ci, CURLOPT_POST, TRUE);
- if (!empty($postfields)) {
- curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);
- $this->postdata = $postfields;
- }
- break;
- case 'DELETE':
- curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE');
- if (!empty($postfields)) {
- $url = "{$url}?{$postfields}";
- }
- }
- if ( isset($this->access_token) && $this->access_token )
- $headers[] = "Authorization: OAuth2 ".$this->access_token;
- $headers[] = "API-RemoteIP: " . $_SERVER['REMOTE_ADDR'];
- curl_setopt($ci, CURLOPT_URL, $url );
- curl_setopt($ci, CURLOPT_HTTPHEADER, $headers );
- curl_setopt($ci, CURLINFO_HEADER_OUT, TRUE );
- $response = curl_exec($ci);
- $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);
- $this->http_info = array_merge($this->http_info, curl_getinfo($ci));
- $this->url = $url;
- if ($this->debug) {
- echo "=====post data======\r\n";
- var_dump($postfields);
- echo '=====info====='."\r\n";
- print_r( curl_getinfo($ci) );
- echo '=====$response====='."\r\n";
- print_r( $response );
- }
- curl_close ($ci);
- return $response;
- }
更详细的参数说明参考:http://cn2.php.net/curl_setopt
PHP魔术方法和魔术常量介绍及使用
PHP中把以两个下划线__
开头的方法称为魔术方法,这些方法在PHP中充当了举足轻重的作用。 魔术方法包括:
__construct()
,类的构造函数__destruct()
,类的析构函数__call()
,在对象中调用一个不可访问方法时调用__callStatic()
,用静态方式中调用一个不可访问方法时调用__get()
,获得一个类的成员变量时调用__set()
,设置一个类的成员变量时调用__isset()
,当对不可访问属性调用isset()
或empty()
时调用__unset()
,当对不可访问属性调用unset()
时被调用。__sleep()
,执行serialize()
时,先会调用这个函数__wakeup()
,执行unserialize()
时,先会调用这个函数__toString()
,类被当成字符串时的回应方法__invoke()
,调用函数的方式调用一个对象时的回应方法__set_state()
,调用var_export()
导出类时,此静态方法会被调用。__clone()
,当对象复制完成时调用
__construct()
和__destruct()
构造函数和析构函数应该不陌生,他们在对象创建和消亡时被调用。例如我们需要打开一个文件,在对象创建时打开,对象消亡时关闭
<?php class FileRead { protected $handle = NULL; function __construct(){ $this->handle = fopen(...); } function __destruct(){ fclose($this->handle); } } ?>
这两个方法在继承时可以扩展,例如:
<?php class TmpFileRead extends FileRead { function __construct(){ parent::__construct(); } function __destruct(){ parent::__destruct(); } } ?>
__call()
和__callStatic()
在对象中调用一个不可访问方法时会调用这两个方法,后者为静态方法。这两个方法我们在可变方法(Variable functions)调用中可能会用到。
<?php class MethodTest { public function __call ($name, $arguments) { echo "Calling object method '$name' ". implode(', ', $arguments). "\n"; } public static function __callStatic ($name, $arguments) { echo "Calling static method '$name' ". implode(', ', $arguments). "\n"; } } $obj = new MethodTest; $obj->runTest('in object context'); MethodTest::runTest('in static context'); ?>
__get()
,__set()
,__isset()
和__unset()
当get/set一个类的成员变量时调用这两个函数。例如我们将对象变量保存在另外一个数组中,而不是对象本身的成员变量
<?php class MethodTest { private $data = array(); public function __set($name, $value){ $this->data[$name] = $value; } public function __get($name){ if(array_key_exists($name, $this->data)) return $this->data[$name]; return NULL; } public function __isset($name){ return isset($this->data[$name]) } public function unset($name){ unset($this->data[$name]); } } ?>
__sleep()
和__wakeup()
当我们在执行serialize()
和unserialize()
时,会先调用这两个函数。例如我们在序列化一个对象时,这个对象有一个数据库链接,想要在反序列化中恢复链接状态,则可以通过重构这两个函数来实现链接的恢复。例子如下:
<?php class Connection { protected $link; private $server, $username, $password, $db; public function __construct($server, $username, $password, $db) { $this->server = $server; $this->username = $username; $this->password = $password; $this->db = $db; $this->connect(); } private function connect() { $this->link = mysql_connect($this->server, $this->username, $this->password); mysql_select_db($this->db, $this->link); } public function __sleep() { return array('server', 'username', 'password', 'db'); } public function __wakeup() { $this->connect(); } } ?>
__toString()
对象当成字符串时的回应方法。例如使用echo $obj;
来输出一个对象
<?php // Declare a simple class class TestClass { public function __toString() { return 'this is a object'; } } $class = new TestClass(); echo $class; ?>
这个方法只能返回字符串,而且不可以在这个方法中抛出异常,否则会出现致命错误。
__invoke()
调用函数的方式调用一个对象时的回应方法。如下
<?php class CallableClass { function __invoke() { echo 'this is a object'; } } $obj = new CallableClass; var_dump(is_callable($obj)); ?>
__set_state()
调用var_export()
导出类时,此静态方法会被调用。
<?php class A { public $var1; public $var2; public static function __set_state ($an_array) { $obj = new A; $obj->var1 = $an_array['var1']; $obj->var2 = $an_array['var2']; return $obj; } } $a = new A; $a->var1 = 5; $a->var2 = 'foo'; var_dump(var_export($a)); ?>
__clone()
当对象复制完成时调用。例如在设计模式详解及PHP实现:单例模式一文中提到的单例模式实现方式,利用这个函数来防止对象被克隆。
<?php public class Singleton { private static $_instance = NULL; // 私有构造方法 private function __construct() {} public static function getInstance() { if (is_null(self::$_instance)) { self::$_instance = new Singleton(); } return self::$_instance; } // 防止克隆实例 public function __clone(){ die('Clone is not allowed.' . E_USER_ERROR); } } ?>
魔术常量(Magic constants)
PHP中的常量大部分都是不变的,但是有8个常量会随着他们所在代码位置的变化而变化,这8个常量被称为魔术常量。
__LINE__
,文件中的当前行号__FILE__
,文件的完整路径和文件名__DIR__
,文件所在的目录__FUNCTION__
,函数名称__CLASS__
,类的名称__TRAIT__
,Trait的名字__METHOD__
,类的方法名__NAMESPACE__
,当前命名空间的名称
这些魔术常量常常被用于获得当前环境信息或者记录日志。
介绍使用php发送邮件类(html格式及附件)
以下为邮件类代码:
<?PHP
class Email {
//---设置全局变量
var $mailTo = ""; // 收件人
var $mailCC = ""; // 抄送
var $mailBCC = ""; // 秘密抄送
var $mailFrom = ""; // 发件人
var $mailSubject = ""; // 主题
var $mailText = ""; // 文本格式的信件主体
var $mailHTML = ""; // html格式的信件主体
var $mailAttachments = ""; // 附件
/* 函数setTo($inAddress) :用于处理邮件的地址 参数 $inAddress
为包涵一个或多个字串,email地址变量,使 用逗号来分割多个邮件地址
默认返回值为true
**********************************************************/
function setTo($inAddress){
//--用explode()函数根据”,”对邮件地址进行分割
$addressArray = explode( ",",$inAddress);
//--通过循环对邮件地址的合法性进行检查
for($i=0;$icheckEmail($addressArray[$i])==false) return false; }
//--所有合法的email地址存入数组中
$this->mailTo = implode($addressArray, ",");
return true; }
/**************************************************
函数 setCC($inAddress) 设置抄送人邮件地址
参数 $inAddress 为包涵一个或多个邮件地址的字串,email地址变量,
使用逗号来分割多个邮件地址 默认返回值为true
**************************************************************/
function setCC($inAddress){
//--用explode()函数根据”,”对邮件地址进行分割
$addressArray = explode( ",",$inAddress);
//--通过循环对邮件地址的合法性进行检查
for($i=0;$icheckEmail($addressArray[$i])==false) return false; }
//--所有合法的email地址存入数组中
$this->mailCC = implode($addressArray, ",");
return true; }
/***************************************************
函数setBCC($inAddress) 设置秘密抄送地址 参数 $inAddress 为包涵一个或多
个邮件地址的字 串,email地址变量,使用逗号来分割多个邮件地址 默认返回值为
true
******************************************/
function setBCC($inAddress){
//--用explode()函数根据”,”对邮件地址进行分割
$addressArray = explode( ",",$inAddress);
//--通过循环对邮件地址的合法性进行检查
for($i=0;$i<COUNT($ADDRESSARRAY);$I++)
{ if($this->checkEmail($addressArray[$i])==false)
return false;
}
//--所有合法的email地址存入数组中
$this->mailBCC = implode($addressArray, ",");
return true;
}
/*****************************************************************
函数setFrom($inAddress):设置发件人地址 参数 $inAddress 为包涵邮件
地址的字串默认返回值为 true
***************************************/
function setFrom($inAddress){
if($this->checkEmail($inAddress)){
$this->mailFrom = $inAddress;
return true;
} return false; }
/**********************
函数 setSubject($inSubject) 用于设置邮件主题参数$inSubject为字串,
默认返回的是true
*******************************************/
function setSubject($inSubject){
if(strlen(trim($inSubject)) > 0){
$this->mailSubject = ereg_replace( "n", "",$inSubject);
return true; }
return false; }
/****************************************************
函数setText($inText) 设置文本格式的邮件主体参数 $inText 为文本内容默
认返回值为true
****************************************/
function setText($inText){
if(strlen(trim($inText)) > 0){
$this->mailText = $inText;
return true; }
return false;
}
/**********************************
函数setHTML($inHTML) 设置html格式的邮件主体参数$inHTML为html格式,
默认返回值为true
************************************/
function setHTML($inHTML){
if(strlen(trim($inHTML)) > 0){
$this->mailHTML = $inHTML;
return true; }
return false; }
/**********************
函数 setAttachments($inAttachments) 设置邮件的附件 参数$inAttachments
为一个包 涵目录的字串,也可以包涵多个文件用逗号进行分割 默认返回值为true
*******************************************/
function setAttachments($inAttachments){
if(strlen(trim($inAttachments)) > 0){
$this->mailAttachments = $inAttachments;
return true; }
return false; }
/*********************************
函 数 checkEmail($inAddress) :这个函数我们前面已经调用过了,主要就是
用于检查email地址的合法性
*****************************************/
function checkEmail($inAddress){
return (ereg( "^[^@ ]+@([a-zA-Z0-9-]+.)+([a-zA-Z0-9-]{2}|net|com|gov|mil|org|edu|int)$",$inAddress));
}
/*************************************************
函数 loadTemplate($inFileLocation,$inHash,$inFormat) 读取临时文件并且
替换无用的信息参 数$inFileLocation用于定位文件的目录
$inHash 由于存储临时的值 $inFormat 由于放置邮件主体
***********************************************************/
function loadTemplate($inFileLocation,$inHash,$inFormat){
/* 比如邮件内有如下内容: Dear ~!UserName~,
Your address is ~!UserAddress~ */
//-- 其中”~!”为起始标志”~”为结束标志
$templateDelim = "~";
$templateNameStart = "!";
//--找出这些地方并把他们替换掉
$templateLineOut = ""; //--打开临时文件
if($templateFile = fopen($inFileLocation, "r")){
while(!feof($templateFile)){
$templateLine = fgets($templateFile,1000);
$templateLineArray = explode($templateDelim,$templateLine);
for( $i=0; $i<COUNT($TEMPLATELINEARRAY);$I++){
//--寻找起始位置
if(strcspn($templateLineArray[$i],$templateNameStart)==0){
//--替换相应的值
$hashName = substr($templateLineArray[$i],1);
//-- 替换相应的值
$templateLineArray[$i] = ereg_replace($hashName,(string)$inHash[$hashName],$hashName);
}
}
//--输出字符数组并叠加
$templateLineOut .= implode($templateLineArray, "");
} //--关闭文件fclose($templateFile);
//--设置主体格式(文本或html)
if( strtoupper($inFormat)== "TEXT" )
return($this->setText($templateLineOut));
else if( strtoupper($inFormat)== "HTML" )
return($this->setHTML($templateLineOut));
} return false;
}
/*****************************************
函数 getRandomBoundary($offset) 返回一个随机的边界值
参数 $offset 为整数 – 用于多管道的调用 返回一个md5()编码的字串
****************************************/
function getRandomBoundary($offset = 0){
//--随机数生成
srand(time()+$offset);
//--返回 md5 编码的32位 字符长度的字串
return ( "----".(md5(rand()))); }
/********************************************
函数: getContentType($inFileName)用于判断附件的类型
**********************************************/
function getContentType($inFileName){
//--去除路径
$inFileName = basename($inFileName);
//--去除没有扩展名的文件
if(strrchr($inFileName, ".") == false){
return "application/octet-stream";
}
//--提区扩 展名并进行判断
$extension = strrchr($inFileName, ".");
switch($extension){
case ".gif": return "image/gif";
case ".gz": return "application/x-gzip";
case ".htm": return "text/html";
case ".html": return "text/html";
case ".jpg": return "image/jpeg";
case ".tar": return "application/x-tar";
case ".txt": return "text/plain";
case ".zip": return "application/zip";
default: return "application/octet-stream";
}
return "application/octet-stream";
}
/**********************************************
函数formatTextHeader把文本内容加上text的文件头
*****************************************************/
function formatTextHeader(){ $outTextHeader = "";
$outTextHeader .= "Content-Type: text/plain;
charset=us-asciin";
$outTextHeader .= "Content-Transfer-Encoding: 7bitnn";
$outTextHeader .= $this->mailText. "n";
return $outTextHeader;
} /************************************************
函数 formatHTMLHeader()把邮件主体内容加上html的文件头
******************************************/
function formatHTMLHeader(){
$outHTMLHeader = "";
$outHTMLHeader .= "Content-Type: text/html;
charset=us-asciin";
$outHTMLHeader .= "Content-Transfer-Encoding: 7bitnn";
$outHTMLHeader .= $this->mailHTML. "n";
return $outHTMLHeader;
}
/**********************************
函数 formatAttachmentHeader($inFileLocation) 把邮件中的附件标识出来
********************************/
function formatAttachmentHeader($inFileLocation){
$outAttachmentHeader = "";
//--用上面的函数getContentType($inFileLocation)得出附件类型
$contentType = $this->getContentType($inFileLocation);
//--如果附件是文本型则用标准的7位编码
if(ereg( "text",$contentType)){
$outAttachmentHeader .= "Content-Type: ".$contentType. ";n";
$outAttachmentHeader .= ' name="'.basename($inFileLocation). '"'. "n";
$outAttachmentHeader .= "Content-Transfer-Encoding: 7bitn";
$outAttachmentHeader .= "Content-Disposition: attachment;n";
$outAttachmentHeader .= ' filename="'.basename($inFileLocation). '"'. "nn";
$textFile = fopen($inFileLocation, "r");
while(!feof($textFile)){
$outAttachmentHeader .= fgets($textFile,1000);
}
//--关闭文件 fclose($textFile);
$outAttachmentHeader .= "n";
}
//--非文本格式则用64位进行编码
else{ $outAttachmentHeader .= "Content-Type: ".$contentType. ";n";
$outAttachmentHeader .= ' name="'.basename($inFileLocation). '"'. "n";
$outAttachmentHeader .= "Content-Transfer-Encoding: base64n";
$outAttachmentHeader .= "Content-Disposition: attachment;n";
$outAttachmentHeader .= ' filename="'.basename($inFileLocation). '"'. "nn";
//--调用外部命令uuencode 进行编码
exec( "uuencode -m $inFileLocation nothing_out",$returnArray);
for ($i = 1; $i<(count($returnArray)); $i++){
$outAttachmentHeader .= $returnArray[$i]. "n";
}
} return $outAttachmentHeader;
}
/******************************
函数 send()用于发送邮件,发送成功返回值为true
************************************/
function send(){
//--设置邮件头为空
$mailHeader = "";
//--添加抄送 人
if($this->mailCC != "")
$mailHeader .= "CC: ".$this->mailCC. "n";
//--添加秘密抄送人
if($this->mailBCC != "")
$mailHeader .= "BCC: ".$this->mailBCC. "n";
//--添加发件人
if($this->mailFrom != "")
$mailHeader .= "FROM: ".$this->mailFrom. "n";
//--------------------------- 邮件格式------------------------------
//--文本格式
if($this->mailText != "" && $this->mailHTML == "" && $this->mailAttachments == ""){
return mail($this->mailTo,$this->mailSubject,$this->mailText,$mailHeader);
}
//--html或text格式
else if($this->mailText != "" && $this->mailHTML != "" && $this->mailAttachments == ""){
$bodyBoundary = $this->getRandomBoundary();
$textHeader = $this->formatTextHeader();
$htmlHeader = $this->formatHTMLHeader();
//--设置 MIME-版本
$mailHeader .= "MIME-Version: 1.0n";
$mailHeader .= "Content-Type: multipart/alternative;n";
$mailHeader .= ' boundary="'.$bodyBoundary. '"';
$mailHeader .= "nnn";
//--添加邮件主体 和边界
$mailHeader .= "--".$bodyBoundary. "n";
$mailHeader .= $textHeader;
$mailHeader .= "--".$bodyBoundary. "n";
//--添加html标 签
$mailHeader .= $htmlHeader;
$mailHeader .= "n--".$bodyBoundary. "--";
//--发送邮件
return mail($this->mailTo,$this->mailSubject, "",$mailHeader);
}
//-- 文本加html加附件
else if($this->mailText != "" && $this->mailHTML != "" && $this->mailAttachments != ""){
$attachmentBoundary = $this->getRandomBoundary();
$mailHeader .= "Content-Type: multipart/mixed;n";
$mailHeader .= ' boundary="'.$attachmentBoundary. '"'. "nn";
$mailHeader .= "This is a multi-part message in MIME format.n";
$mailHeader .= "--".$attachmentBoundary. "n";
$bodyBoundary = $this->getRandomBoundary(1);
$textHeader = $this->formatTextHeader();
$htmlHeader = $this->formatHTMLHeader();
$mailHeader .= "MIME-Version: 1.0n";
$mailHeader .= "Content-Type: multipart/alternative;n";
$mailHeader .= ' boundary="'.$bodyBoundary. '"';
$mailHeader .= "nnn";
$mailHeader .= "--".$bodyBoundary. "n";
$mailHeader .= $textHeader;
$mailHeader .= "--".$bodyBoundary. "n";
$mailHeader .= $htmlHeader;
$mailHeader .= "n--".$bodyBoundary. "--";
//--获取附件值
$attachmentArray = explode( ",",$this->mailAttachments);
//--根据附件的个数进行循环
for($i=0;$i<COUNT($ATTACHMENTARRAY);$I++){
//--分割 $mailHeader .= "n--".$attachmentBoundary. "n";
//--附件信息
$mailHeader .= $this->formatAttachmentHeader($attachmentArray[$i]);
}
$mailHeader .= "--".$attachmentBoundary. "--";
return mail($this->mailTo,$this->mailSubject, "",$mailHeader);
}
return false;
}
}
?>
使用方法:
<?
Include “email.class”
$mail->setTo("a@a.com "); //收件人
$mail-> setCC("b@b.com ,[url=mailto:c@c.com]c@c.com[/url]"); //抄送
$mail-> setCC("d@b.com , [url=mailto:e@c.com]e@c.com[/url]"); //秘密抄送
$mail->setFrom(“[url=mailto:f@f.com]f@f.com[/url]”); //发件人
$mail->setSubject(“主题”) ; //主题
$mail->setText(“文本格 式”) ;//发送文本格式也可以是变量
$mail->setHTML(“html格式”) ;//发送html格式也可以是变量
$mail->setAttachments(“c:a.jpg”) ;//添加附件,需表明路径
$mail->send(); //发送邮件
?>