竹磬网-邵珠庆の日记 生命只有一次,你可以用它来做些更多伟大的事情–Make the world a little better and easier


28月/170

介绍一下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地址。

115月/170

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"

73月/160

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、 一个抓取网页的简单案例:

[php][/php] view plain copy
  1. // 创建一个新cURL资源  
  2. $ch = curl_init();  
  3.   
  4. // 设置URL和相应的选项  
  5. curl_setopt($ch, CURLOPT_URL, "http://www.baidu.com/");  
  6. curl_setopt($ch, CURLOPT_HEADER, false);  
  7.   
  8. // 抓取URL并把它传递给浏览器  
  9. curl_exec($ch);  
  10.   
  11. //关闭cURL资源,并且释放系统资源  
  12. curl_close($ch);  

2、POST数据案例:

[php][/php] view plain copy
  1. // 创建一个新cURL资源  
  2. $ch = curl_init();  
  3. $data = 'phone='. urlencode($phone);  
  4. // 设置URL和相应的选项  
  5. curl_setopt($ch, CURLOPT_URL, "http://www.post.com/");  
  6. curl_setopt($ch, CURLOPT_POST, 1);  
  7. curl_setopt($ch, CURLOPT_POSTFIELDS, $data);  
  8. // 抓取URL并把它传递给浏览器  
  9. curl_exec($ch);  
  10.   
  11. //关闭cURL资源,并且释放系统资源  
  12. 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部分截取(部分我增加了点注释,全当参数翻译下。哈哈) 有兴趣的自己研究,自己挪为己用。嘿嘿

[php][/php] view plain copy
  1. /** 
  2.      * Make an HTTP request 
  3.      * 
  4.      * @return string API results 
  5.      * @ignore 
  6.      */  
  7.     function http($url, $method, $postfields = NULL, $headers = array()) {  
  8.         $this->http_info = array();  
  9.         $ci = curl_init();  
  10.         /* Curl settings */  
  11.         curl_setopt($ci, CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_0);//让cURL自己判断使用哪个版本  
  12.         curl_setopt($ci, CURLOPT_USERAGENT, $this->useragent);//在HTTP请求中包含一个"User-Agent: "头的字符串。  
  13.         curl_setopt($ci, CURLOPT_CONNECTTIMEOUT, $this->connecttimeout);//在发起连接前等待的时间,如果设置为0,则无限等待  
  14.         curl_setopt($ci, CURLOPT_TIMEOUT, $this->timeout);//设置cURL允许执行的最长秒数  
  15.         curl_setopt($ci, CURLOPT_RETURNTRANSFER, TRUE);//返回原生的(Raw)输出  
  16.         curl_setopt($ci, CURLOPT_ENCODING, "");//HTTP请求头中"Accept-Encoding: "的值。支持的编码有"identity","deflate"和"gzip"。如果为空字符串"",请求头会发送所有支持的编码类型。  
  17.         curl_setopt($ci, CURLOPT_SSL_VERIFYPEER, $this->ssl_verifypeer);//禁用后cURL将终止从服务端进行验证  
  18.         curl_setopt($ci, CURLOPT_HEADERFUNCTION, array($this, 'getHeader'));//第一个是cURL的资源句柄,第二个是输出的header数据  
  19.         curl_setopt($ci, CURLOPT_HEADER, FALSE);//启用时会将头文件的信息作为数据流输出  
  20.   
  21.         switch ($method) {  
  22.             case 'POST':  
  23.                 curl_setopt($ci, CURLOPT_POST, TRUE);  
  24.                 if (!empty($postfields)) {  
  25.                     curl_setopt($ci, CURLOPT_POSTFIELDS, $postfields);  
  26.                     $this->postdata = $postfields;  
  27.                 }  
  28.                 break;  
  29.             case 'DELETE':  
  30.                 curl_setopt($ci, CURLOPT_CUSTOMREQUEST, 'DELETE');  
  31.                 if (!empty($postfields)) {  
  32.                     $url = "{$url}?{$postfields}";  
  33.                 }  
  34.         }  
  35.   
  36.         if ( isset($this->access_token) && $this->access_token )  
  37.             $headers[] = "Authorization: OAuth2 ".$this->access_token;  
  38.   
  39.         $headers[] = "API-RemoteIP: " . $_SERVER['REMOTE_ADDR'];  
  40.         curl_setopt($ci, CURLOPT_URL, $url );  
  41.         curl_setopt($ci, CURLOPT_HTTPHEADER, $headers );  
  42.         curl_setopt($ci, CURLINFO_HEADER_OUT, TRUE );  
  43.   
  44.         $response = curl_exec($ci);  
  45.         $this->http_code = curl_getinfo($ci, CURLINFO_HTTP_CODE);  
  46.         $this->http_info = array_merge($this->http_info, curl_getinfo($ci));  
  47.         $this->url = $url;  
  48.   
  49.         if ($this->debug) {  
  50.             echo "=====post data======\r\n";  
  51.             var_dump($postfields);  
  52.   
  53.             echo '=====info====='."\r\n";  
  54.             print_r( curl_getinfo($ci) );  
  55.   
  56.             echo '=====$response====='."\r\n";  
  57.             print_r( $response );  
  58.         }  
  59.         curl_close ($ci);  
  60.         return $response;  
  61.     }  

更详细的参数说明参考:http://cn2.php.net/curl_setopt

 
 
111月/150

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__,当前命名空间的名称

这些魔术常量常常被用于获得当前环境信息或者记录日志。

245月/100

介绍使用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(); //发送邮件
?>