[C#]asp.net上传RAR文件自动解压

mikel阅读(832)

using System;
using System.IO;
using System.Diagnostics;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Web.Security;

www.25175.net


using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
namespace WebLayer
{
/**//// <summary>
/// WebForm1 的摘要说明。
/// </summary>
public class WebForm1 : System.Web.UI.Page
{
  protected System.Web.UI.WebControls.Button Button1;
  protected System.Web.UI.HtmlControls.HtmlInputFile myfile;

  private void Page_Load(object sender, System.EventArgs e)
  {
   // 在此处放置用户代码以初始化页面
  }

  Web 窗体设计器生成的代码#region Web 窗体设计器生成的代码
  override protected void OnInit(EventArgs e)
  {
   //
   // CODEGEN: 该调用是 ASP.NET Web 窗体设计器所必需的。
   //
   InitializeComponent();
   base.OnInit(e);
  }
 
  /**//// <summary>
  /// 设计器支持所需的方法 – 不要使用代码编辑器修改
  /// 此方法的内容。
  /// </summary>
  private void InitializeComponent()
  {   
   this.Button1.Click += new System.EventHandler(this.Button1_Click);
   this.Load += new System.EventHandler(this.Page_Load);

  }
  #endregion

  private void Button1_Click(object sender, System.EventArgs e)
  {
   string path = @"C:\"+myfile.PostedFile.FileName.Substring(myfile.PostedFile.FileName.LastIndexOf("\\"));
   myfile.PostedFile.SaveAs(path);
string file=path+myfile.PostFile.FileName;
   Response.Write("文件上传成功:"+path);
   //Response.End();
   // 在此处放置用户代码以初始化页面 
   Process p = new Process();  
   p.StartInfo.UseShellExecute = false;  
   p.StartInfo.RedirectStandardInput = true;  
   p.StartInfo.RedirectStandardOutput = true;  
   p.StartInfo.RedirectStandardError = true;  
   p.StartInfo.CreateNoWindow = true; 
   p.StartInfo.FileName = "cmd.exe";  
   p.Close();  
   //解压Rar文件 
   string ServerDir=@"C:\Program Files\WinRAR";//rar路径 
   System.Diagnostics.Process Process1=new Process(); 
   Process1.StartInfo.FileName=ServerDir+"\\Rar.exe"; 
   Directory.CreateDirectory(path+".files"); //创建解压文件夹 
   Process1.StartInfo.Arguments=" x -inul -y "+file+" "+path+".files"; 
   Process1.Start();//解压开始 
   while(!Process1.HasExited)           //等待解压的完成 
   { 
   } 
   //File.Delete(path);//删除rar文件 
  }
}
}

转载:http://blog.csdn.net/RandomLife/archive/2004/09/22/113102.aspx

使用RAR版本:WinRAR 3.20 beta 2(© 1993-2003 Eunege Roshal )
用法:     rar <命令>-<开关 1> -<开关 N> <压缩文件> <文件…>
               <@列表文件…> <解压路径\>
<命令>

a

添加文件到压缩文件

c

添加压缩文件注释

cf

添加文件注释

cw

写入压缩文件注释到文件

d

删除压缩文件中的文件

e

解压压缩文件到当前目录

f

刷新压缩文件中的文件

i[参数]=<>

在压缩文件中查找字符串

k

锁定压缩文件

l[t,b]

列出压缩文件[技术信息,简洁]

m[f]

移动到压缩文件[仅对文件]

p

打印文件到标准输出设备

r

修复压缩文件

rc

重建丢失的卷

rn

重命名压缩文件

rr[N]

添加数据恢复记录

rv[N]

创建恢复卷

s[名字|-]

转换压缩文件为自解压格式或转换回压缩文件

t

测试压缩文件

u

更新压缩文件中的文件

v[t,b]

详细列出压缩文件[技术信息,简洁]

x

用绝对路径解压文件

<开关>

停止扫描

ac

压缩或解压后清除文件属性

ad

添加压缩文件名到目标路径

ag[格式]

使用当前日期生成压缩文件名

ao

添加具有压缩属性的文件

ap<格式>

添加路径到压缩文件中

as

同步压缩文件内容

av

添加用户身份校验(仅注册版本可用)

av-

禁用用户身份校验

c-

禁用注释显示

cfg-

禁用读取配置

cl

名称转换为小写

cu

名称转换为大写

df

压缩后删除文件

dh

打开共享文件

ds

对固实压缩文件禁用名称排序

e<属性>

设置文件排除属性

ed

不添加空目录

en

不添加"压缩文件结束"标志

ep

从名称中排除路径

ep1

从名称中排除基本目录

ep2

展开为完整路径

f

刷新文件

hp[密码]

同时加密文件数据和文件头

idp

禁用百分比显示

ieml[属性]

E-mail发送压缩文件

ierr

发送所有消息到标准错误设备

ilog[名称]

把错误写到日志文件(只有注册版本可用)

inul

禁用所有消息

ioff

完成一个操作后关闭PC电源

isnd

启用声音

k

锁定压缩文件

kb

保留损坏的已解压文件

m<0..5>

设置压缩级别(0-存储…3-默认…5-最大)

mc<参数>

设置高级压缩参数

md<大小>

KB为单位的字典大小(64,128,256,512,1024,2048,4096 or A-G)

ms[ext;ext]

指定存储的文件类型

o+

覆盖已存在文件

o-

不覆盖已存在文件

os

保存NTFS

ow

保存或恢复文件所有者和组

p[密码]

设置密码

p-

不询问密码

r

递归子目录

r0

仅递归通配符名称的子目录

ri<P>[:<S>]

设置优先级(0-默认,1-最小..15-最大)和以毫秒为单位的休眠时间

rr[N]

添加数据恢复记录

rv[N]

创建恢复卷

s[<N>,v[-],e]

创建固实压缩文件

s-

禁用固实压缩文件

sfx[名称]

创建自解压压缩文件

t

压缩后测试文件

ta<日期>

添加日期<日期>后修改的文件,日期格式YYYYMMDDHHMMSS

tb<日期>

添加日期<日期>前修改的文件,日期格式YYYYMMDDHHMMSS

tk

保留原始压缩文件时间

tl

设置压缩文件时间为最新文件时间

tn<时间>

添加<时间>以后的文件

to<时间>

添加<时间>以前的文件

ts<m,c,a>[N]

保存或恢复文件时间(修改,创建,访问)

u

更新文件

v

自动检测创建卷的大小或者列出所有的卷

v<大小>[k,b]

创建卷大小=<大小>*1000[*1024, *1]

vd

创建容量前清除磁盘内容

ver[n]

文件版本控制

vn

使用旧风格的卷命名方案

vp

每卷之前暂停

w<路径>

指定工作目录

x<文件>

排除指定的文件

x@

从标准输入设备读取要排除的文件名

x@<列表>

排除指定列表文件中的文件

y

假设对全部询问都回答是

z<文件>

从文件读取压缩文件注释

示例:
1、rar a file file.ext
如果file.rar不存在将创建file.rar文件;如果file.rar压缩包中已有file.ext,将更新压缩包中的file.ext;还可用d:\*.ext代替file.ext将d盘下所有ext文件(不包括自文件夹)添加到压缩包中。
2、rar a -r -v2000 -s -sfx -rr file
从当前文件夹和子文件夹压缩全部文件成为 2000000 字节大小、固实的、分卷自解压文件 file.part1.exe,file.part2.rar,file.part3.rar 等,并在每一个分卷中添加恢复记录;将命令a换成命令m可将文件压缩后删除
3、rar x Fonts *.ttf
会从压缩文件解压 *.ttf 字体文件到当前文件夹,但下面命令:
    rar x Fonts *.ttf NewFonts\
会从压缩文件解压 *.ttf 字体文件到文件夹 NewFont
4、rar a -pZaBaToAd -r secret games\*.*
使用密码 ZaBaToAd 来将文件夹“games”的内容添加到压缩文件“secret”
************************
    Powered By RandomLife
         2004年9月22日
************************

[C#]ASP.Net File Upload/Download Module Version 2

mikel阅读(906)

Introduction

Version 2 (beta 1) of the ASP.NET file upload control is now available in the downloads section of this site. Version 2 brings many enhancements over the orignal component including handlers which allow for storage and download of files using SQL Server databases.

The previous four posts have outlined how version 2 differs from the original component. This post gives the installation instructions and release notes for the beta. For details of what the component does, refer to the original article and these posts:

Installation

Installation is simple. Just copy the FileUploadLibrary.dll file into bin folder of your web application and set up the web.config and resources according to the instructions in the following sections. Although the library is shipped with a Visual Studio 2008 solution, it is developed for ASP.NET 2.0 and above.

Web.Config settings

Step 1 – install the HTTP module

The HTTP module intercepts incoming file upload requests and sends them off to the selected processors. For example, if you are using the SQL Server processor then the module will split the incoming request and pass each file to the SQL Server processor, which will in turn store the files in the database. To install the module, place the following code in web.config:

1.<system.web>
2.  <httpModules>
3.    <add name="upload_module" type="darrenjohnstone.net.FileUpload.UploadModule, FileUploadLibrary"/>
4.  </httpModules>
5.</system.web>

Step 2 – install the progress handler

The progress bar gets it’s status updates from an HTTP handler which returns an XML message containing the status of the file upload. This is a light weight and efficient mechanism for getting these reports as it returns a very small message pulled directly from memory on the server. To get progress reports the HTTP handler must be installed in web.config:

1.<system.web>
2.  <httpHandlers>
3.      <add verb="GET" type="darrenjohnstone.net.FileUpload.UploadProgressHandler, FileUploadLibrary" path="UploadProgress.ashx"/>
4.  </httpHandlers>
5.</system.web>

IIS 7 setup

To set up the module and handler for IIS 7, the handlers and module settings are required in the system.webServer section of web.config rather than as above:

01.<system.webServer>
02.    <modules>
03.        <remove name="upload_module"/>
04.        <add name="upload_module" type="darrenjohnstone.net.FileUpload.UploadModule, FileUploadLibrary"/>
05.    </modules>
06.    <handlers>
07.        <add name="UploadProgress" verb="GET" type="darrenjohnstone.net.FileUpload.UploadProgressHandler, FileUploadLibrary" path="UploadProgress.ashx"/>
08.  </handlers>
09.</system.webServer>

A note about request limits

ASP.Net enforces request limits on applications. These ensure that an individual request never exceeds a pre-set maximum. They exist to prevent denial of service attacks where a bad person can cause your server to go down by frequently sending requests which it can’t handle, thus forcing it to spend most of it’s resources dealing with the problem request to the exclusion of other requests. I think it’s important to mention because request limits aren’t a bad thing- they are an important security feature.

Of course request limits can prevent large files being uploaded, but they’re not the problem. ASP.Net has problems handling large files because it runs out of memory. The upload module solves this by handling memory more efficiently and dealing with files in chunks. The module will still respect the maximum request limits.

In IIS 6 the maximum request limit is set using the maxRequestLength parameter in web.config. In addition to this it is wise to set the executionTimeout parameter to prevent the process from timing out before the file is uploaded. The following example shows how these can be set to 100Mb and 1 hour respectively:

1.<httpRuntime executionTimeout="3600" maxRequestLength="40960" />

In version 1 of the module the maxRequestLength setting was completely bypassed. In hindsight I think that was probably a bad thing so in version 2 I’ve added in code to ensure that it is respected and that the request is ended if the value is exceeded.

Things are a little different in IIS 7 however. The IIS 7 request filters by default will kick in and limit the maximum content length before the module even gets a chance to do anything. To allow larger uploads we need to set the maximumAllowedContentLength in web.config by entering the statement shown below at a command prompt. This example sets the maximum content length to 100Mb for the web app called “WebApp” on the default web site.


%windir%\system32\inetsrv\appcmd set config "Default Web Site/WebApp" -section:requestFiltering -requestLimits.maxAllowedContentLength:104857600

Note that in IIS 6 the maxRequestLength is in kilobytes while in IIS 7 the maxAllowedContentLength setting is in bytes.

Selecting and configuring a processor

Two processors are provided with the upload module- SQLProcessor and FileSystemProcessor, these store uploaded files in a SQL Server database table or in the file system respectively. You also have the option of creating your own processors by implementing the IFileProcessor interface.

For the upload module to work you must select and configure one processor. Selection of a processor is handled in the global.asax file during the Application_Start event. Here you need to set the processor type and buffer size. You then handle the ProcessorInit event of the UploadManager singleton class in order to set any extra properties (such as a connection string for the SQLProcessor) in your processor when the module initialises it.

01.void Application_Start(object sender, EventArgs e)
02.{
03.    //Uncomment one of the following lines to select a processor
04. 
05.    //UploadManager.Instance.BufferSize = 1024;
06.    //UploadManager.Instance.ProcessorType = typeof(FileSystemProcessor);
07. 
08.    UploadManager.Instance.ProcessorType = typeof(SQLProcessor);
09.    UploadManager.Instance.ProcessorInit += new FileProcessorInitEventHandler(Processor_Init);
10.}

In the Processor_Init event handler you then set up the processor how you want it:

01.void Processor_Init(object sender, FileProcessorInitEventArgs args)
02.{
03.    if (args.Processor is FileSystemProcessor)
04.    {
05.        FileSystemProcessor processor;
06. 
07.        processor = args.Processor as FileSystemProcessor;
08. 
09.        // Set up the download path here - default to the root of the web application
10.        processor.OutputPath = @"c:\uploads";
11.    }
12. 
13.    if (args.Processor is SQLProcessor)
14.    {
15.        SQLProcessor processor;
16. 
17.        processor = args.Processor as SQLProcessor;
18. 
19.        // Set up the connection string
20.        processor.ConnectionString = "server=(local);initial catalog=FileUpload;integrated security=true";
21.    }
22.}

If you are using the SQL Server processor then set the connection string to your database and create a new table for uploads using this script:

01.Create TABLE [dbo].[UploadedFile](
02.    [Id] [int] IDENTITY(1,1) NOT NULL,
03.    [FileName] [varchar](100) NOT NULL,
04.    [ContentType] [varchar](50) NOT NULL,
05.    [FileContents] [image] NOT NULL,
06. CONSTRAINT [PK_UploadedFiles] PRIMARY KEY CLUSTERED
07.(
08.    [Id] ASC
09.)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
10.) ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]

The UploadedFile table contains an identity column which is used to provide a unique identifier to the upload.

Setting up the resources

The upload control requires a number of images, JavaScript, and CSS files in order to function. These are normally held in the upload_scripts, upload_images, and upload_styles folders which are placed in the root of the web application. Get these folders from the demo application and put them into your web app. The folder structure should look similar to the following image:

If you need to change this then see the next section on configuring the controls.

Configuring the controls

Now that the HTTP module has been configured, any file uploads from standard ASP.Net file inputs will be automatically intercepted and streamed to the chosen provider. However, this is only part of the story. We can also get a progress bar which shows the percentage completed of the uploads and which file the processor is working on at any given time.

A replacement for the standard file input control has also been provided. The new DJFileUpload control can accept multiple file inputs and offers skinning support.

Each page that is to use DJFileUpload controls must have an instance of the DJUploadController control at the top of the page before any upload controls. This control is responsible for emitting all of the required JavaScript and also for showing the progress bar when the form is submitted.

The DJUploadController control has a number of properties that can be set:

Property Description Default value
ScriptPath The path to the upload_scripts folder which is included in the demo project. This folder contains the scripts needed to make the UI components work. upload_scripts/
ImagePath The path to the upload_images folder which is included in the demo project. This folder contains the images used by the upload skin along with all of the buttons. upload_images/
CSSPath The path to the upload_styles folder which is included in the demo project. This folder contains the styles needed to skin the UI components. upload_styles/
ShowCancelButton Set to true to show a cancel button on the progress bar. The cancel button causes the upload to be terminated when it is clicked. true
ShowProgressBar Set to true to automatically show an upload progress bar when the form is submitted. Set to false to disable the progress bar or to use the DJFileUpload control without the HTTP module. true
AllowedFileExtensions A comma separated list of file extensions to allow in the upload control (e.g. .png,.gif,.jpg) or an empty string to allow all file extensions. An empty string to allow all file extensions.

In most cases the default values of these properties will suffice. This is especially true if the upload_scripts, upload_images, and upload_styles folders are placed in the root of the web application.

Once the DJUploadController control has been added you can add as many DJFileUpload or normal ASP.Net FileUpload controls as required. The DJFileUpload control has the following configuration properties.

Property Description Default value
InitialFileUploads The number of file boxes to show initially in the upload control. 1
MaxFileUploads The maximum number of files to allow the user to upload via the upload control. 5
ShowAddButton true to show the add button on the control allowing users to add new file boxes. true
ShowUploadButton true to show an upload button on the control which will cause the form to be submitted. In most cases there will be a separate submit button. Any submit button will cause the upload to start. false

A simple page with a single file upload control would be marked up similar to the following:

01.<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="Default.aspx.cs" Inherits="FileUploadV2._Default" %>
02.<%@ Register assembly="FileUploadLibrary" namespace="darrenjohnstone.net.FileUpload" tagprefix="cc1" %>
03. 
04.<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
06.<head id="PageHeader" runat="server">
07.    <title>File Upload Demonstration</title>
08.</head>
09.<body>
10.    <form id="MainForm" runat="server">
11.        <cc1:DJUploadController ID="DJUploadController1" runat="server" ShowCancelButton="true" AllowedFileExtensions=".zip,.jpg,.png" />
12. 
13.        <cc1:DJFileUpload ID="DJFileUpload1" runat="server" ShowAddButton="true" ShowUploadButton="true" />
14.    </form>
15.</body>
16.</html>

Producing a screen like this:

Getting at the uploaded files

Once the upload has completed the Status property of the controller can be used to retrieve a list of all files which were uploaded and any where errors were encountered. The file name is available along with any unique identifier provided by the file processor. In the event of an error the exception is provided.

01.protected void Page_Load(object sender, EventArgs e)
02.{
03.    if (Page.IsPostBack && DJUploadController1.Status != null)
04.    {
05.        StringBuilder sb = new StringBuilder();
06. 
07.        sb.Append("<div class='up_results'>");
08.        sb.Append("<h3>Files uploaded</h3>");
09.        sb.Append("<ul>");
10. 
11.        foreach (UploadedFile f in DJUploadController1.Status.UploadedFiles)
12.        {
13.            sb.Append("<li>");
14.            sb.Append(f.FileName);
15. 
16.            if (f.Identifier != null)
17.            {
18.                sb.Append(" ID = ");
19.                sb.Append(f.Identifier.ToString());
20.            }
21. 
22.            sb.Append("</li>");
23.        }
24. 
25.        sb.Append("</ul>");
26. 
27.        sb.Append("<h3>Files with errors</h3>");
28.        sb.Append("<ul>");
29. 
30.        foreach (UploadedFile f in DJUploadController1.Status.ErrorFiles)
31.        {
32.            sb.Append("<li>");
33.            sb.Append(f.FileName);
34. 
35.            if (f.Identifier != null)
36.            {
37.                sb.Append(" ID = ");
38.                sb.Append(f.Identifier.ToString());
39.            }
40. 
41.            if (f.Exception != null)
42.            {
43.                sb.Append(" Exception = ");
44.                sb.Append(f.Exception.Message);
45.            }
46. 
47.            sb.Append("</li>");
48.        }
49. 
50.        sb.Append("</ul>");
51.        sb.Append("</div>");
52.        ltResults.Text = sb.ToString();
53.    }
54.}

In the case of the SQLProcessor the Status.Identifier property will be set to the Id of the item in the database.

Downloading from SQL Server

If you are using the SQLProcessor to upload files into SQL Server, then I’ve also provided code in that class for downloading the files as a stream. The SQLFileProcessor class has two extra methods not shared with other IFileProcessor implementations.

01./// <summary>
02./// Gets the file name and content type of the file.
03./// </summary>
04./// <param name="id">The ID of the file to get.</param>
05./// <param name="fileName">File name.</param>
06./// <param name="contentType">Content type.</param>
07./// <returns>True if the file is found, otherwise false.</returns>
08.public virtual bool GetFileDetails(int id, out string fileName, out string contentType)
09.{
10.....
11.}
12. 
13./// <summary>
14./// Gets the file from the database and writes it to a stream.
15./// </summary>
16./// <param name="stream">Stream to write to.</param>
17./// <param name="id">The id of the record to get.</param>
18./// <param name="blockSize">The size of blocks to stream the data in.</param>
19.public virtual void SaveFileToStream(Stream stream, int id, int blockSize)
20.{
21.....
22.}

The GetFileDetails method is used to get the name and content type of a file from the database with the given ID whilst the SaveFileToStream method is used to get the blob data of the stored file and write it to a stream in chunks. Together these methods allow files to be retrieved from the database and manipulated or downloaded. A good example of this is the SQLFileDownloadHandler class which implements a simple HTTP handler allowing a file to be downloaded. The relatively simple code for the handler is shown below:

01./// <summary>
02./// An HTTP handler which allows files to be downloaded from a SQL database.
03./// </summary>
04.public class SQLFileDownloadHandler : IHttpHandler
05.{
06.    SQLProcessor _processor;
07. 
08.    #region Constructor
09. 
10.    /// <summary>
11.    /// Initializes a new instance of the <see cref="SQLFileDownloadHandler"/> class.
12.    /// </summary>
13.    public SQLFileDownloadHandler()
14.    {
15.        _processor = UploadManager.Instance.GetProcessor() as SQLProcessor;
16. 
17.        if (_processor == null)
18.        {
19.            throw new Exception("The processor must be of type SQLProcessor for downloads.");
20.        }
21.    }
22. 
23.    #endregion
24. 
25.    #region IHttpHandler Members
26. 
27.    /// <summary>
28.    /// Gets a value indicating whether another request can use the <see cref="T:System.Web.IHttpHandler"/> instance.
29.    /// </summary>
30.    /// <value></value>
31.    /// <returns>true if the <see cref="T:System.Web.IHttpHandler"/> instance is reusable; otherwise, false.</returns>
32.    public bool IsReusable
33.    {
34.        get
35.        {
36.            return false;
37.        }
38.    }
39. 
40.    /// <summary>
41.    /// Enables processing of HTTP Web requests by a custom HttpHandler that implements the <see cref="T:System.Web.IHttpHandler"/> interface.
42.    /// </summary>
43.    /// <param name="context">An <see cref="T:System.Web.HttpContext"/> object that provides references to the intrinsic server objects (for example, Request, Response, Session, and Server) used to service HTTP requests.</param>
44.    public void ProcessRequest(HttpContext context)
45.    {
46.        int id;
47.        string contentType;
48.        string fileName;
49. 
50.        if (int.TryParse(context.Request["id"], out id))
51.        {
52.            if (_processor.GetFileDetails(id, out fileName, out contentType))
53.            {
54.                context.Response.ContentType = contentType;
55. 
56.                if (context.Request["attach"] == "yes")
57.                {
58.                    context.Response.AddHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
59.                }
60. 
61.                _processor.SaveFileToStream(context.Response.OutputStream, id, UploadManager.Instance.BufferSize);
62.                context.Response.Flush();
63.            }
64.        }
65.    }
66. 
67.    #endregion
68.}

In this case the Id of the file is read from a corresponding URL parameter. A second URL parameter (attach) simply causes the file name and content disposition to be configured for an attachment when it is set to “yes”. This simply causes the browser to initiate a file download rather than displaying the file inline as it would for an image.

If you want to use the download handler in you applications you need to add it to the web.config just like the others:

1.<httpHandlers>
2.  <add verb="GET" type="darrenjohnstone.net.FileUpload.SQLFileDownloadHandler, FileUploadLibrary" path="DownloadFile.ashx"/>
3.</httpHandlers>

and for IIS 7

1.<system.webServer>
2.    <handlers>
3.    <add name="FileDownload" verb="GET" type="darrenjohnstone.net.FileUpload.SQLFileDownloadHandler, FileUploadLibrary" path="DownloadFile.ashx"/>
4.  </handlers>
5.</system.webServer>

Once this is done simply use a hyperlink to download the file:

1.<a href="DownloadFile.ashx?ID=1&attach=yes">Download the file</a>

Creating a custom processor

You can create your own custom processor by implementing the IFileProcessor interface in a custom class. For a good example of this read about how the SQLProcessor was implemented in this previous post: ASP.Net File Upload Revisited – Part 3, Uploading to SQL Server.

Component dependencies (or rather not)

Whilst the HTTP module and UI components are designed to work together, there is no requirement for this. The HTTP module will intercept all file uploads, including those from standard ASP.Net FileUpload controls. There is no need to use the DJFileUpload control if it is not required.

Conversely, the DJFileUpload control can be used without the HTTP module as a direct replacement for the ASP.Net FileUpload control if all that is required is skinning support or file extension filtering. To do this, the ShowProgressBar property of the DJUploadController control on the page must be set to false.

Object model reference

For the techies out there, here is the current object model of the library (click to make it bigger). This might help to make some of the previous explanations clearer. In addition to this, the previous four posts also give a great deal more technical information.

[MVC]ASP.NET MVC Multiple File Upload

mikel阅读(1828)

This blog entry is part of a series of entries on using ASP.NET MVC to build an entire Family Video Website from scratch. Before reading this entry, you might want to read the previous four entries:

Family Video Website #1 – Upload the Videos – In this entry, I create an MVC controller that accepts large file uploads.

Family Video Website #2 –Add the Database – In this entry, I added a database so that I could associate additional information, such as a title and description, with each video.

Family Video Website #3 – Play Videos with Silverlight – In this entry, I added the ASP.NET MediaPlayer Silverlight player to the application.

Family Video Website #4 – Paging, Silverlight, and Flip – In this entry, I add paging to the application and demonstrate how you can encode and upload videos recorded with a Flip video camera.

Accepting File Uploads

The standard HTML <input type=”file” /> element does not work well when you need to upload large files (see Figure 1). It doesn’t display a progress bar. When you initiate the upload, your browser freezes. You have no idea whether something is happening or not.

The standard HTML <input type=”file” /> element also does not provide you with a method of uploading multiple files at once. Typically, I dump a large number of pictures from my camera onto my hard drive and I want to upload several of these pictures to the Family website. The standard HTML file upload element forces you to upload the files, laboriously, one at a time.

Figure 1 – The standard HTML file upload element

image

For these reasons, I decided to investigate alternatives to the standard HTML file upload element. I investigated both Ajax and Silverlight solutions.

Using Ajax for File Uploads

My first inclination was to implement an Ajax solution for accepting file uploads. Using Ajax, you can continuously poll the server from the browser to check on the progress of uploading a file. In that way, you can display a progress bar.

I found good reviews of different Ajax file upload solutions for ASP.NET in Matt Berseth’s blog and Jon Galloway’s blog at the following addresses:

http://mattberseth.com/blog/2008/07/aspnet_file_upload_with_realti_1.html

http://weblogs.asp.net/jgalloway/archive/2008/01/08/large-file-uploads-in-asp-net.aspx

After reading Matt Berseth’s positive review of two open source Ajax file upload components, named NeatUpload and the ASP.Net File Upload/Download Module, I experimented with using these components in an ASP.NET MVC application. You can download these components from the following URLs:

http://www.brettle.com/neatupload

http://darrenjohnstone.net/2008/07/15/aspnet-file-upload-module-version-2-beta-1/

I made some progress in adapting these components to work in the context of an ASP.NET MVC application. However, after reading Jon Galloway’s blog, I decided to investigate a Silverlight solution to the problem of accepting file uploads.

Using Silverlight for File Uploads

When I need an answer to a Silverlight question, I turn to either Tim Heuer or Jesse Liberty who are the Silverlight gurus on my team. Tim recommended that I look into the following two Silverlight controls:

http://sandbox.inetsolution.com/fileuploadwebsite/FileUploaderTestPage.aspx

http://www.michielpost.nl/Silverlight/MultiFileUploader/

Both of these Silverlight controls enable you to upload multiple files. However, the first control is commercial and the second control is open source (the author says that the control will be released as open source with the Silverlight 2.0 release). Therefore, I decided to use the second control, the Multi File Uploader control, for the Family Videos Website application.

The Multi File Uploader is made of two parts. The user interface for accepting a file upload is created with a Silverlight control. You display the file upload user interface by adding a Silverlight control named mpost.SilverlightMultiFileUpload.xap to your project.

The Silverlight control is embedded in the Create.aspx view in Listing 1. The Create view enables you to upload new videos or pictures to the Family Video Website (see Figure 2). You can use the upload control to upload multiple pictures or videos at the same time.

Figure 2 – Using the Multi File Uploader Silverlight control

image

Listing 1 – Views\Media\Create.aspx

  1. <%@ Page Language="VB" AutoEventWireup="false" CodeBehind="Create.aspx.vb" Inherits="FamilyVideos.Create" %>  
  2. <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">  
  3. <html xmlns="http://www.w3.org/1999/xhtml" >  
  4. <head id="Head1" runat="server">  
  5.     <title>Add New Media</title>  
  6. </head>  
  7. <body>  
  8.     <div>  
  9.       
  10.     <h1>Upload Media</h1>  
  11.   
  12.   
  13. <%–          
  14.     MaxFileSizeKB:     Maximum file size in KBs. <br />  
  15.     MaxUploads:     Maximum number of simultaneous uploads <br />  
  16.     FileFilter:    File filter, for example ony jpeg use: FileFilter=Jpeg (*.jpg) |*.jpg <br />  
  17.     CustomParam: Your custom parameter, anything here will be available in the WCF webservice <br />  
  18. –%>  
  19.     <div id="silverlightControlHost">  
  20.         <object data="data:application/x-silverlight," type="application/x-silverlight-2-b2" width="500" height="260">  
  21.             <param name="source" value="/mpost.SilverlightMultiFileUpload.xap"/>  
  22.             <param name="initParams" value="MaxFileSizeKB=50000,MaxUploads=2,FileFilter=,CustomParam=yourparameters" />  
  23.             <a href="http://go.microsoft.com/fwlink/?LinkID=115261" style="text-decoration: none;">  
  24.                  <img src="http://go.microsoft.com/fwlink/?LinkId=108181" alt="Get Microsoft Silverlight" style="border-style: none"/>  
  25.             </a>  
  26.         </object>  
  27.     </div>  
  28.   
  29.   
  30.     <a href="/Home/Index">Finished Uploading</a>  
  31.   
  32.       
  33.     </div>  
  34. </body>  
  35. </html>  

 

The Silverlight control is embedded in the Create.aspx view with the help of an HTML <object> tag. The <object> tag includes a source parameter that points to the mpost.SilverlightMultiFileUpload.xap file in the project.

Notice that the <object> tag also contains an initParams parameter. You can use this parameter to configure several options for the Multi File Uploader control such as the maximum allowable size of an uploaded file.

The second part of the Multi File Uploader control is a WCF service. The Silverlight control calls the WCF service to pass the file being uploaded from the browser to the web server.

In order to use the service, you must add a reference to your project to the mpost.FileUploadServiceLibrary.dll assembly. This assembly contains a base WCF service that you can use as the base class for your WCF service.

The WCF service used by the Family Videos application is contained in Listing 2 and the code-behind class for this service is contained in Listing 3.

Listing 2 – SilverlightUploadService.svc

  1. <%@ ServiceHost   
  2.   Language="VB"   
  3.   Debug="true"   
  4.   Service="FamilyVideos.SilverlightUploadService"  
  5.   CodeBehind="SilverlightUploadService.svc.vb" %>  

Listing 3 – SilverlightUploadService.svc.vb

  1. Imports System.IO  
  2. Imports System.Web.Hosting  
  3.   
  4. Public Class SilverlightUploadService  
  5.     Inherits mpost.FileUploadServiceLibrary.UploadService  
  6.   
  7.   
  8.     Protected Overrides Sub FinishedFileUpload(ByVal fileName As StringByVal parameters As String)  
  9.         ' Create new media object  
  10.         Dim newMedia As New Media()  
  11.         newMedia.Title = "New Media"  
  12.         newMedia.FileName = fileName  
  13.         newMedia.Description = "No Description"  
  14.         newMedia.EntryDate = DateTime.Now  
  15.   
  16.         ' Add new media object to database  
  17.         Dim repository As New MediaRepository()  
  18.         repository.Insert(newMedia)  
  19.   
  20.         ' Rename file  
  21.         Dim oldName = GetFullPath(fileName)  
  22.         Dim newName = GetFullPath(newMedia.MediaName)  
  23.         File.Move(oldName, newName)  
  24.     End Sub  
  25.   
  26.     Protected Overrides Function GetUploadFolder() As String  
  27.         Return Globals.UploadPath  
  28.     End Function  
  29.   
  30.   
  31.     Private Function GetFullPath(ByVal fileName As StringAs String  
  32.         Return HostingEnvironment.ApplicationPhysicalPath + "/" + GetUploadFolder() + "/" + fileName  
  33.     End Function  
  34.   
  35.   
  36.   
  37. End Class  

When you create a service to use with the Multi File Uploader control, you override two methods of the base UploadService class. You override both the GetUploadFolder() and FinishedFileUpload() methods.

The GetUploadFolder() method returns the path to the folder where the file is uploaded. The FinishedFileUpload() method is called after the file is finished uploading. In Listing 3, the FinishedFileUpload() method is used to add a new Media item to the database that represents a newly uploaded file.

Finally, in order to get the Multi File Uploader control to work, you must add configuration information to your web configuration (web.config) file for the WCF service. The Family Videos application uses the system.serviceModel configuration section in Listing 4.

Listing 4 – web.config

  1. <system.serviceModel>  
  2.     <serviceHostingEnvironment aspNetCompatibilityEnabled="true" />  
  3.     <behaviors>  
  4.         <serviceBehaviors>  
  5.             <behavior name="FamilyVideos.SilverlightUploadServiceBehavior">  
  6.                 <serviceMetadata httpGetEnabled="true"/>  
  7.                 <serviceDebug includeExceptionDetailInFaults="true"/>  
  8.             </behavior>  
  9.         </serviceBehaviors>  
  10.     </behaviors>  
  11.     <services>  
  12.         <service behaviorConfiguration="FamilyVideos.SilverlightUploadServiceBehavior"   
  13.             name="FamilyVideos.SilverlightUploadService">  
  14.             <endpoint address="" binding="basicHttpBinding" contract="mpost.FileUploadServiceLibrary.IUploadService">  
  15.                 <identity>  
  16.                     <dns value="localhost"/>  
  17.                 </identity>  
  18.             </endpoint>  
  19.             <endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>  
  20.         </service>  
  21.     </services>  
  22. </system.serviceModel>  

 

The Multi File Uploader works quite nicely with Firefox (see Figure 3). This means that the Family Video Website works great with both Internet Explorer and Firefox.

Figure 3 – Multi file Uploader used in Firefox

image

Summary

I’m very happy with the new method of uploading files described in this blog entry. The Silverlight control solution solves both of the problems associated with the standard HTML file upload element discussed in the beginning of this blog entry. First, the Silverlight control provides you with visual feedback on the progress of a file being uploaded. Second, it enables you to efficiently upload multiple files at a time (for example, all of the pictures that you dump to your hard drive from your digital camera).

There is still more work to do on the Family Videos Website. For example, we still need to tackle missing pieces of the application such as form validation and authentication.

Download the Code

[C#]在ASP.NET应用程序中上传文件

mikel阅读(794)

  在Web程序中上传文件是很常见的需求。利用HTTP协议上传文件的方式非常有限,最常见的莫过于使用<input type="file" />元素进行上传。这种上传方式会将内容使用multipart/form-data方案进行编码,并将内容POST到服务器端。使用 multipart/form-data编码方式与默认的application/x-url-encoded编码方式相比,在大数据量情况下效率要高很 多。

  使用<input type="file" />上传文件最大的优势在于编程方便,几乎各种服务器端技术都对这种上传方式做了良好的封装,使得程序员能够直观地对客户端上传的文件进行处理。不 过总体来说,这个协议并不适合做文件传输,解析数据流内容的代价相对较高,并且没有一些例如断点续传的机制来辅助,导致在上传大文件时经常会力不从心。

  有朋友认为使用<input type="file" />上传文件最大的问题在于内存占用太高,由于需要将整个文件载入内存进行处理,导致如果用户上传文件太大,或者同时上传的用户太多,会造成服务器 端内存耗尽。这个观点其实是错误的。对于某些服务器端的技术,例如Spring Framework,或者早期ASP.NET 1.1时,为了供程序处理,都会将用户上传的内容完全载入内存,这的确会带来问题。但是其实协议本身并没有规定服务器端应该使用何种方式来处理上传的文 件。例如在现在的ASP.NET 2.0中就已经会在用户上传数据超过一定数量之后将其存在硬盘中的临时文件中,而这点对于开发人员完全透明,也就是说,开发人员可以像以前一样进行数据流 的处理。

  ASP.NET 2.0启用硬盘临时文件的阈值(threshold)是可配置的:

<system.web>
  <httpRuntime
    maxRequestLength="Int32"
    requestLengthDiskThreshold="Int32" />
</system.web>

  maxRequestLength自不必说,刚接触ASP.NET的朋友总会发现上传文件不能超过4M,这就是因为 maxRequestLength的大小默认为4096,这就限制着每个请求的大小不得超过4096KB。这么做的目的是为了保护应用程序不受恶意请求的 危害。当请求超过maxRequestLength之后,ASP.NET处理程序将不会处理该请求。这里和ASP.NET抛出一个异常是不同的,这就是为 什么如果用户上传文件太大,看到的并非是ASP.NET应用程序中指定的错误页面(或者默认的),因为ASP.NET还没有对这个请求进行处理。 requestLengthDiskThreshold就是刚才所提到的阈值,其默认值为256,即一个请求内容超过256KB时就会启用硬盘作为缓存。 这个阈值理论上和客户端是否是在上传内容无关,只要客户端发来的请求大于这个值即可。因此,在ASP.NET 2.0中服务器的内存不会因为客户端的异常请求而耗尽。

  如果我们需要在ASP.NET(如果没有特别说明,以下ASP.NET均指ASP.NET 2.0)应用中上传文件,我们一般就会直接使用<asp:FileUpload />控件进行文件上传。如果一个页面中存在<asp:FileUpload />控件,那么页面中form元素的enctype就会被自动改为multipart/form-data,而且我们可以在页面PostBack之 后通过<asp:FileUpload />控件的引用来获得客户端通过该控件所上传得文件。不过,如果上传文件的功能需要较为特别的需求——例如需要进度条提 示,<asp:FileUpload />控件就无能为力了。

  确切地说,应该是<input type="file" />所能提供的支持非常有限,因此一些特殊需求我们不能实现——严格说来,应该是无法轻易地、直接地实现。这样,在实现这些功能时,我们就会绕一个 大大的弯。为了避免每次实现相同功能时都要费神费时地走一遍弯路,因此出现了各种上传组件。上传组件提供了封装好的功能,使得我们在实现文件上传功能时变 得轻松了很多。例如几乎所有的上传组件都直接或间接地提供了进度提示的功能,有的提供了当前的百分比数值,有的则直接提供了一套UI;有的组件只提供了简 单的UI,有的却提供了一整套上传、删除的管理界面。此外,有的组件还提供了防止客户端恶意上传的能力。

  关于ASP.NET下的上传组件,最广为流传的方式莫过于在ASP.NET Pipeline的BeginRequest事件中截获当前的HttpWorkerRequest对象,然后直接调用其ReadEntityBody等方 法获取客户端传递过来的数据流,并加以分析和处理。在ASP.NET 1.1时期,这么做的目的是为了直接将数据写入硬盘,以避免上传内容消耗太多服务器内存,但是现在自然已经不会因为这个原因而这么做了。从客户端发起请求 到一定规模的数据传输完毕需要一段时间,那么从HttpWorkerRequest对象中读取数据流自然需要一段时间,而在这段时间内,客户端可以使用新 的请求进行轮询来获得当前上传的状况。这就是获得上传进度的最传统的做法。这个做法的原理很容易理解,但是写出一个完整的组件其实很不容易,尤其是各种细 节方面的问题会让人感到防不胜防。此类组件中最成功且最著名的莫过于NeatUpload了。

  NeatUpload是一个开源组件,使用LGPL(Lesser General Public License)许 可协议,也就是说它是“business-friendly”的。NeatUpload可以在ASP.NET和mono中使用,能够将上传的文件存在硬盘 中或者SQL Server数据库中。NeatUpload提供了两个服务器控件:<NeatUpload:InputFile> 和<NeatUpload:ProgressBar>。前者用于代替<asp:FileUpload />,可以通过它访问到用户通过特定上传框上传的内容;后者则是一个进度条显示控件,负责使用弹出窗口或内联的形式显示上传的进度。弹出窗口自不必 说,而所谓的“内联”方式其实只是在页面中嵌入一个Iframe元素,然后通过不断刷新iframe中的页面来进行进度展示而已——可见它和弹出窗口显示 方式的区别仅仅在页面所处的位置。当然,如果我们希望将其移植为AJAX形式也不难,只需开发一个页面,继承NeatUpload提供的 ProgressPage类,并通过ProgressPage所提供的一些属性(总字节数,已上传字节数,已花时间,etc.)来获得当前上传的进度,最 后直接使用Response.Write输出JSON形式的数据即可。事实上原本在iframe(或新窗口)中的页面,也是继承了 ProgressPage类,并且使用HTML的方式进行呈现而已,本质上并没有太大区别。

  不过个人认为,其实NeatUpload的实用价值不高(这点稍后再述),它最大的意义还在于提供了一个完整的优秀的示例。 NeatUpload设计精巧,注释完整,是个不可多得学习案例。如果能够将NeatUpload的代码研究一遍,那么相信在编程能力和ASP.NET的 理解上都会上一个新的台阶。此外,在NeatUpload站点上还能够发现NeatHtml。NeatHtml是一个开源的Web组件,用于显示不安全的内容(主要是用户输入内容,例如博客评论,论坛帖子等等),主要用于避免跨站脚本(XSS,Cross-Site Scripting)等安全问题。作为组件的作者,Dean还将NeatHtml所用到的技术总结为一篇Whitepaper,感兴趣的朋友可以看一下,这是一份不可多得的技术资料。

   顺便提一下,个人认为目前很多开发人员的编程能力还不够,似乎很多人都过早地把精力放在了“设计”,或者某个特定的技术上,而忽略了最基础的“编程能 力”,也就是将一段思路转化为代码实现的能力。我发现,很多朋友在解决问题的时候,似乎都能很快得到解决方案并且叙述出来,但是真正要使用代码来表现出来 时却显得困难重重。其实在工作中,思路或解决方案可以通过讨论而获得,但是真正转化为代码的时候只能靠自己了。而且编程能力其实和所谓的“工作经验”无 关,我建议以“应届毕业生”“自居”的朋友,可以定心地锻炼一下自己的编程能力。

  与NeatUpload类似的开源组件还有Memba Velodoc XP Edition,它是Velodoc文件管理系统的核心。不过严格说来,这不仅仅是一个上传组件,而是一套文件管理的解决方案,它包含:

  1. 一个兼容IIS 7集成管道模式的ASP.NET Http Module,支持大文件上传使用(有趣的是,NeatUpload申明,IIS 7的一个Bug使它无法在IIS 7集成管道模式中使用)。
  2. 一个支持断点续传的ASP.NET Http Handler。
  3. 一系列ASP.NET服务器端控件,提供了文件上传功能所需的UI,包括一个多文件上传控件,一个ListView控件和一个进度条控件。
  4. 一个Web应用程序,可以替换FTP的交换文件方式,支持Email发送链接。它也是上面所提到的组件的使用示例。
  5. 一个Windows Service,用于定期清理旧文件。
  6. 一个测试项目、一个部署项目、以及一个安装项目。
  7. 文档。

  回到NeatUpload组件。说实话,我始终不喜欢这种进度获取方式,因为我觉得通过一个额外的请求对服务器进行轮询无疑是一个累赘。事实 上,如果需要上传大文件并且获得上传进度,目前最好的方式应该是使用RIA方式。最典型的RIA上传方式就是利用Flash了。ActionScript 2.0中已经存在FileReference和FileReferenceList组件以支持单文件和多文件的上传,有了这两个组件,上传的各种信息已经 能够完全在客户端获得,而上传进度也自然能够计算出来。FileReference和FileReferenceList组件非常容易使用,就连像我这样 对Flash一窍不通的人,也能在短时间内作出一个简单的上传功能。但是自从有了swfupload,世界就变得更美好了。

  严格说来,通过FileReference所得到的上传进度是“客户端发送数据的进度”,而像NeatUpload的做法得到的是“服务器端接受数据的进度”,两者不可混为一谈。

  swfupload也是个开源组件,顾名思义是使用Flash进行上传。不过对于swfupload来说,Flash的作用主要是“控制”,而 不是“展示”,这无疑给了开发人员更大的灵活性。swfupload的实现方式自然是利用了FileReference和 FileReferenceList组件所提供的功能,通过Flash与JavaScript的交互能力,使得开发文件上传功能变得非常优雅和容易。有了 swfupload,开发人员可以使用JavaScript来实现各种显示方式,开发像Flicker一样酷酷的上传界面也不再是非常困难的事情了。

  swfupload是个客户端组件,它对于服务器端来说完全透明,也就是说,服务器端只需要使用对待普通form的方式来处理即可。例如在 ASP.NET中我们可以使用Generic Handler来处理客户端的文件上传。如下,fileCollection变量即为客户端Post至服务器端所有文件的集合,我们可以使用name或下 标的方式来获得其中的HttpPostedFile对象。:

public class UploadHandler : IHttpHandler
{
    public void ProcessRequest(HttpContext context)
    {
        HttpFileCollection fileColllection = context.Request.Files;
        …
    }
 
    public bool IsReusable {}
}

  既然Flash提供了文件上传功能,Silverlight作为微软主推的RIA技术也不会缺了这项功能。这篇文章源自Silverlight 2.0的Quick Starts,展示了如何使用Silverlight 2.0开发文件上传的功能,感兴趣的朋友可以一读。

  围绕着ASP.NET中上传文件这个话题也讨论了不少了,还有什么没有涉及到的吗?个人认为其实至少还有一个非常重要问题是没有讨论过,那就是 在处理上传文件时占用ASP.NET处理线程的问题。众所周知,ASP.NET处理请求时会用到线程池中的线程,当线程池中的线程被用完之后没有被处理的 请求只能排队了。因此增大ASP.NET应用程序吞吐量的一个重要手段,就是为一些耗时的操作使用异步处理方式(事实上这一命题可以在大部分应用中成 立)。例如一个数据库查询操作需要3秒钟,如果不使用异步操作,处理线程就会被阻塞,直至查询完成。如果使用异步方式来执行数据库查询,在这3秒钟内线程 就可以用户处理其他请求,当异步操作结束之后,ASP.NET就会使用另一个线程来继续处理这个请求。

  上传大文件也是一个长时间占用处理线程的工作,而且遗憾的是,这无法使用异步操作来完成(通过异步操作来释放处理线程需要操作系统的支持,因此 只有少量功能可以使用异步操作)。如果一个文件上传需要3分钟时间,那么在这3分钟内就会独占一个处理线程,如果上传文件的连接一多,就会大大影响应用程 序的性能——就像遭受了某种方式的DOS攻击一样。因此,即使使用了像NeatUpload和swfupload这样的组件,也无法解决上传连接过多造成 可用线程减少的问题。要解决这个问题并不容易,以下是两种思路(欢迎大家就此问题进行讨论):

  • 扩展IIS,使上传文件或处理文件的过程不经ASP.NET处理,以减少ASP.NET应用程序线程的消耗。现在有了IIS 7,如果使用集成管道模式,应该也可以使用托管代码进行扩展。
  • 使用额外的ASP.NET应用程序处理文件上传,以节省上传文件的线程对原ASP.NET应用程序线程的消耗。

[JavaScript]SWFUpload2.2中文帮助

mikel阅读(799)

SWFUpload V2.2.0 说明文档

更新时间:2008-11-07

TOC

  1. SWFUpload
  2. SWFUpload 2
  3. 概述
  4. 入门
  5. SWFUpload JavaScript 对象
    1. 构造器
    2. 全局变量和常量
      1. instances
      2. movieCount
      3. QUEUE_ERROR
      4. UPLOAD_ERROR
      5. FILE_STATUS
      6. Default Event Handlers
      7. BUTTON_ACTION(added in v2.2.0)
      8. BUTTON_CURSOR(added in v2.2.0)
      9. BUTTON_WINDOW_MODE(added in v2.2.0)
    3. 属性
      1. customSettings
      2. movieName
    4. 方法
      1. addSetting (不推荐使用)
      2. getSetting (不推荐使用)
      3. retrieveSetting (v2.1.0中已删除)
      4. destroy (v2.1.0中新增)
      5. displayDebugInfo
      6. selectFile (不推荐使用)
      7. selectFiles (不推荐使用)
      8. startUpload
      9. cancelUpload
      10. stopUpload
      11. getStats
      12. setStats
      13. getFile
      14. addPostParam
      15. removePostParam
      16. addFileParam
      17. removeFileParam
      18. setUploadURL
      19. setPostParams
      20. setFileTypes
      21. setFileSizeLimit
      22. setFileUploadLimit
      23. setFileQueueLimit
      24. setFilePostName
      25. setUseQueryString
      26. setDebugEnabled
      27. setButtonImageURL (added in v2.2.0)
      28. setButtonDimensions (added in v2.2.0)
      29. setButtonText (added in v2.2.0)
      30. setButtonTextStyle (added in v2.2.0)
      31. setButtonTextPadding (added in v2.2.0)
      32. setButtonDisabled (added in v2.2.0)
      33. setButtonAction (added in v2.2.0)
      34. setButtonCursor (added in v2.2.0)
    5. 事件
      1. flashReady
      2. swfUploadLoaded
      3. fileDialogStart
      4. fileQueued
      5. fileQueueError
      6. fileDialogComplete
      7. uploadStart
      8. uploadProgress
      9. uploadError
      10. uploadSuccess
      11. uploadComplete
      12. debug
    6. SWFUpload 功能对象
      1. Settings Object
      2. Settings Description
      3. File Object
      4. Stats Object
  6. SWFUpload 插件(未译)
  7. 存在的问题(未译)

SWFUpload

SWFUpload最初是由Vinterwebb.se开发的一个客户端的上传工具. 它结合了FLASH和JavaScript的功能,以提供一种超越了传统的浏览器中<input type="file" />标签提供的文件上传功能。

SWFUpload提供的主要功能:

  • 在文件选择对话框中能够进行文件多选
  • 页面无刷新的上传
  • 提供上传进度的事件回调,实时显示上传进度
  • 良好的浏览器兼容性
  • 采用了命名空间以兼容其它JS的库 (例如 JQuery, Prototype, 等等)
  • 对FLASH 8和FLASH 9播放器的支持
  • 对FLASH 9和FLASH 10播放器的支持(V2.2.0版本放弃了对Flash 8的支持)

SWFUpload背后的设计思想和其它基于Flash的上传工具是不同的。它将浏览器的中UI交给开发人员来控制。开发人员能够利用 XHTML,CSS,JavaScript来定制符合他们网站风格的UI上传元素。然后使用它提供的一组简单的JS事件来更新上传状态,开发人员能够利用 这些事件来及时更新页面中的上传进度UI。

不幸的是Flash Player 10 更严格的安全机制迫使我们不得不将一个Flash Button放入Flash影片中。SWFUpload提供API供开发者通过图片、文字、CSS的方式来自定制更灵活的UI显示。

SWFUpload v2

SWFUpload v2包含了新的高级功能,改善了稳定性,解决了FlashPlayer中的一些bug,并且提供一套有用的插件。新的功能包括:

  • 兼容了Flash Player 10的安全限制问题
  • 在文件上传的同时能够发送额外的POST数据
  • 针对每一个文件上传发送POST/GET数据
  • 更直观的事件回调
  • 动态修改实例设置
  • 接收服务端返回的数据
  • 非取消形式的停止文件上传
  • 自定义上传的顺序
  • 支持单文件、多文件的文件的选择
  • 文件入队数量,文件上传数量和文件大小的限制
  • 更合理地处理0字节的文件
  • 针对每个文件在上传前都提供一个最后确认的时间回调
  • 解决了v1.0.2版本中未描述到的关于Flash的bug
  • 解决的v1.0.2中的bug:
    • 在IE中,刷新的时候FLASH无法加载(详细可见我之前的debug过程
    • 在FireFox中,如果窗口的滚动条没有回滚到顶部,那么Flash无法加载
    • Race-conditions when files are cached
  • 兼容ASP.NET Forms

SWFUpload v2 延续了SWFUpload的设计目标,将UI分离以交给开发人员控制和后续扩展

概述

传统的HTML上传

标准的HTML上传表单为用户提供一个文本框和按钮来选择文件,选中的文件是随着form表单提交的。整个文件上传完成之后,下一个页面才会显示,并且不能对选择的文件做预设的文件检验,例如文件大小限制,文件类型限制。当文件上传时,用户获得的可用的反馈信息很少。

传统的HTML上传模式十分简单,线性的,几乎所有浏览器都支持它。

SWFUpload

SWFUpload使用一个隐藏的Flash影片来控制文件的选择和上传。JavaScript用来激活文件选择对话框。 此文件选择对话框是可以设置允许用户选择一个单独的文件或者是多个文件。
SWFUpload使用一个Flash影片来控制文件的选择和上传。此FLASH中包含一个用户自定制UI的按钮,点击该按钮能够激活Flash本身的高级文件上传对话框,它能够根据用户的设置来进行单文件或者是多文件的上传。 选择的的文件类型也是可以被限制的,因此用户只能选择指定的适当的文件,例如*.jgp;*.gif。

提醒:Flash Player 10的安全机制更严格,类似打开文件上传的对话框的操作,一定需要用户交互才触发,如果用脚本触发,会报#2176的运行时错误。因此V2.2.0版本在SWF中添加了一个可定制的Button让用户交互来打开文件对话框。

当选定文件以后,每个文件都会被验证和处理。当Flash上传文件的时候,由开发人员预定义的Javascript事件会被定时触发以便来更新页面中的UI,同时还提供上传状态和错误信息。

选定的文件的上传和它所在页面、表单是独立的。每个文件都是单独上传的,这就保证了服务端脚本能够在一个时间点更容易地处理单个文件。虽然Flash提供 了上传服务,但是页面并不会提交或者重新载入。相比于标准的HTML Form,SWFUpload的使用方式更像是AJAX程序,页面中的Form会和FLASH控制的文件上传单独处理。

入门

SWFUpload并不是拖放式的上传控件,它需要JavaScript和DOM的知识。一些可用的演示展示了它能够完成什么事情以及它是如何完成这些常见的任务。

SWFUpload由4部分组成:

  1. 初始化和设置(Javascript)
  2. JavaScript 库: SWFUpload.js
  3. Flash控制元素: SWFUpload_f8.swf 或者 SWFupload_f9.swf SWFUpload.swf(V2.2.0版本放弃了对flash 8的支持)
  4. 事件处理(Javascript)

使用SWFUpload遇到的多数问题是由不正确地设置或者定义了糟糕的处理事件引起的。

初始化和设置

SWFpload必须在页面中初始化,一般可以在window.onload事件中完成此操作。它的构造函数需要一个Object类型的设置对象。 这个设置对象一般是一个直接定义的Object类型变量,直接传递给SWFUpload的构造函数。

初始化的SWFUpload对象的引用需要保留下来,因为当显示文件选择对话框和启动文件上传的时候需要这个实例的引用。

例如:用直接定义的Object类型变量设置初始化SWFUpload对象

var swfu; window.onload = function () { swfu = new SWFUpload({ upload_url : "http://www.swfupload.org/upload.php", flash_url : "http://www.swfupload.org/swfupload.swf", button_placeholder_id : "spanSWFUploadButton", file_size_limit : "20480" }); };

例如:用存储在变量中的设置对象初始化SWFUpload对象

var swfu; window.onload = function () { var settings_object = { upload_url : "http://www.swfupload.org/upload.php", flash_url : "http://www.swfupload.org/swfupload.swf", button_placeholder_id : "spanSWFUploadButton", file_size_limit : "20480" }; swfu = new SWFUpload(settings_object); };

JavaScript 库

该JavaScript库文件(swfupload.js)应该包含在需要上传功能的页面中。

当SWFUpload创建完成并能访问它的一系列功能时,开发人员可以来控制此实例。

例如: 添加SWFUpload.js到页面中

<script type="text/javascript" src="http://www.swfupload.org/swfupload.js"></script>

例如: 根据需要的设置来初始化SWFUpload,同时把它的seleteFiles方法绑定到一个按钮的Click事件上。

var swfu = new SWFUpload({ upload_url : "http://www.swfupload.org/upload.php", flash_url : "http://www.swfupload.org/swfupload.swf", button_placeholder_id : "spanSWFUploadButton" }); document.getElementById("BrowseButton").onclick = function () { swfu.selectFiles(); };

Flash 控制元素

SWFUpload JavaScript库动态加载Flash控制元素(swfupload.swf)。该 Flash控制元素有两个版本。swfupload_f8.swf支持Flash Player8以及更高版本。它在提供了更好的兼容性同时牺牲了一些功能。swfupload_f9.swf支持Flash Player9.0.28以及更高版本。它在提供了额外的功能同时牺牲了使用Flash Player8的用户。

Flash控制元素的文件地址在初始化的时候就应该在SWFUpload设置对象中定义。

Flash控制元素是一个很小的的Flash影片,它提供了文件浏览、检验和上传功能。它在页面中展现给用户的是一个UI可自定制的按钮,但该Flash会在需要时候通过与Javascript通信来通知浏览器处理更新。

事件处理

开发人员必须定义一系列JavaScript函数来处理SWFUpload事件回调,当一些不同的重要事件发生的时候,这些函数会被触发。

通过处理SWFUpload的事件,开发人员能够提供关于上传进度、出错信息以及上传完成等的信息反馈。

例如: swfupload的处理事件和初始化

// uploadStart处理事件。该函数变量在设置对象中指定给了upload_start_handler属性。 var uploadStartEventHandler = function (file) { var continue_with_upload; if (file.name === "the sky is blue") { continue_with_upload = true; } else { continue_with_upload = false; } return continue_with_upload; }; //uploadSuccess处理事件。 该函数变量在设置对象中指定给了upload_success_handler属性。 var uploadSuccessEventHandler = function (file, server_data) { alert("The file " + file.name + " has been delivered to the server."); alert("The server responded with " + server_data); }; //创建SWFUpload实例,设置事件回调函数 var swfu = new SWFUpload({ upload_url : "http://www.swfupload.org/upload.php", flash_url : "http://www.swfupload.org/swfupload.swf", file_size_limit : "20480", upload_start_handler : uploadStartEventHandler, upload_success_handler : uploadSuccessEventHandler });

SWFUpload JavaScript 对象

构造函数

SWFUpload(settings object)

返回:一个SWFUpload 实例

var swfupload_instance = new SWFUpload(settings_object);

全局变量和常量

SWFUpload定义了一些全局变量和常量,这对SWFUpload的高级应用程序和处理错误都是很有用的,它们都是只读的。

SWFUpload.instances

SWFUpload.instances 是一个存储了页面中所有SWFUpload实例引用的数组。Flash播放器依靠这个数组来调用正确的处理事件。该数组是由movieName属性来索引 的关联数组。例如:SWFUpload.instances.SWFUpload_0访问的是第一个实例引用。

注意: SWFUpload.instances不是一个真正的JavaScript数组,实际上它是一个对象(关联数组)。

SWFUpload.movieCount

SWFUpoad.movieCount是一个全局变量,用于记录页面中的SWFUpload实例个数,同时确保给每一个Flash影片分配一个惟一的movieName。

SWFUpload.QUEUE_ERROR

SWFUpload.QUEUE_ERROR是一个包含了Queue Error错误码的JS对象,一般用它来查看fileQueueError事件的中发送的错误码,以确定fileQueueError的具体类型。

SWFUpload.QUEUE_ERROR = { QUEUE_LIMIT_EXCEEDED : -100, FILE_EXCEEDS_SIZE_LIMIT : -110, ZERO_BYTE_FILE : -120, INVALID_FILETYPE : -130 };

SWFUpload.UPLOAD_ERROR

SWFUpload.UPLOAD_ERROR是一个包含了Upload Error错误码的JS对象,一般用它来查看uploadError事件的中发送的错误码,以确定uploadError的具体类型。

SWFUpload.UPLOAD_ERROR = { HTTP_ERROR : -200, MISSING_UPLOAD_URL : -210, IO_ERROR : -220, SECURITY_ERROR : -230, UPLOAD_LIMIT_EXCEEDED : -240, UPLOAD_FAILED : -250, SPECIFIED_FILE_ID_NOT_FOUND : -260, FILE_VALIDATION_FAILED : -270, FILE_CANCELLED : -280, UPLOAD_STOPPED : -290 };

SWFUpload.FILE_STATUS

SWFUpload.FILE_STATUS是一个包含File Status状态码的JS对象。它可以用来检测File对象中的file status属性,以确定文件的状态。

SWFUpload.FILE_STATUS = { QUEUED : -1, IN_PROGRESS : -2, ERROR : -3, SUCCESS : -4, CANCELLED : -5 };

默认处理事件

SWFUpload库提供了一系列默认的处理事件。当开发人员没有自定义处理事件时,SWFUpload库将调用这些默认的处理事件。因此当自定义事件时,不要把这些默认的处理事件覆盖了。自定义事件是需要在settings对象中被单独定义的。

SWFUpload.BUTTON_ACTION

SWFUpload.BUTTON_ACTION是一个包含button的动作预设的JS对象。

SWFUpload.BUTTON_ACTION = { Select_FILE : -100, Select_FILES : -110, START_UPLOAD : -120 }

可 以使用button_action属性来设置Flash本身的文件上传对话框的行为。默认为 SWFUpload.BUTTON_ACTION.Select_FILES,点击按钮将会打开多文件上传的对话框。如果设置为 SWFUpload.BUTTON_ACTION.Select_FILE,则为单文件上传。如果设置为 SWFUpload.BUTTON_ACTION.START_UPLOAD,则启动文件上传

SWFUpload.CURSOR

SWFUpload.CURSOR是一个包含button的光标状态码的JS对象。

SWFUpload.CURSOR = { ARROW : -1, HAND : -2 }

可以使用button_cursor属性来设置鼠标划过button时的光标状态。默认为SWFUpload.CURSOR.ARROW,如果设置为SWFUpload.CURSOR.HAND,则为手形

SWFUpload.WINDOW_MODE

SWFUpload.WINDOW_MODE是一个包含了该SWF插入到页面中的wmode属性的JS对象.可以通过设置button_window_mode属性来告诉浏览器具体以哪种模式显示此SWF。

SWFUpload.WINDOW_MODE = { WINDOW : "window", TRANSPARENT : "transparent", OPAQUE : "opaque" };

SWFUpload.WINDOW_MODE.WINDOW是默认的模式. 该SWF将位于页面元素的最高层级。

SWFUpload.WINDOW_MODE.OPAQUE 该SWF可以被页面类的其他元素通过层级的设置来覆盖它。

SWFUpload.WINDOW_MODE.TRANSPARENT 该SWF的背景是透明的,可以透过它看到背后的页面元素。

属性

下面这个列表是相关属性的具体描述。使用其它属性或者对只读属性进行了写的操作都会造成SWFUpload出现问题。

customSettings (可读/可写)

customSettings属性是一个空的JavaScript对象,它被用来存储跟SWFUpload实例相关联的数据。它的内容可以使用设置对象中的custom_settings属性来初始化。

注意:一些插件使用customSettings对象来实现它们的内部控制。当重写整个customSettings对象的时候需要务必小心。

例如:

// 初始化包含自定义设置的SWFUpload对象 var swfu = new SWFUpload({ custom_settings : { custom_setting_1 : "custom_setting_value_1", custom_setting_2 : "custom_setting_value_2", custom_setting_n : "custom_setting_value_n", } }); swfu.customSettings.custom_setting_1 = "custom_setting_value_1"; // 更改一个存在的自定义设置 swfu.customSettings.myNewCustomSetting = "new custom setting value"; // 添加一个新的自定义设置 //用一个全新的对象重写customSettings swfu.customSettings = { custom_setting_A : "custom_setting_value_A", custom_setting_B : "custom_setting_value_B" };

movieName(只读)

包含了该SWFUpload实例的惟一影片名字。该值被传递给Flash,用来完成Flash和JavaScript的通信。该值被用来索引实例在SWFUpload.instances数组中的位置,你无法更改此值。

方法

下面的方法用来操作SWFUpload。其中有些方法可以跟元素(例如,按钮)的点击事件绑定,其它的方法供SWFUpload内部处理事件中调用。

object addSetting(setting_name, value, default_value)

不赞成使用 V2.1.0源码中注释:addSetting和getSetting已经不再被使用了,只是考虑到兼容V2版本,才继续保留在库中。

object getSetting(setting_name)

不赞成使用 V2.1.0源码中注释:addSetting和getSetting已经不再被使用了,只是考虑到兼容V2版本,才继续保留在库中。

object retrieveSetting(setting_value, default_value)

v2.1.0中已被删除

bool destroy()

v2.1.0中新增

用于将一个SWFUpload实例从页面中销毁。不但删除DOM中的Flash元素,同时还删除SWFUpload实例的相关引用。成功返回true,失败返回false。

这个方法还没有针对插件做兼容测试,可能会有不兼容问题。(尤其是SWFObject插件)

提醒:SWFUpload在v2.1.0中改写了Flash插入的代码,V2版中使用SWFObject插入Flash会造成IE的一个刷新BUG

void displayDebugInfo()

调用Debug方法,在Debug输出框中显示SWFUpload实例的设置信息,如果设置中的debug属性是true,那么默认是在实例化完成以后自动调用此方法。

void selectFile()

不赞成使用,不兼容Flash Player 10

弹出flash的文件选择对话框,只能选择单个文件。

提醒:Flash Player 10的安全机制更严格,类似打开文件上传的对话框的操作,一定需要用户交互才触发,如果用脚本触发,会报#2176的运行时错误。因此V2.2.0版本在SWF中添加了一个可定制的Button让用户交互来打开文件对话框。

void selectFiles()

不赞成使用,不兼容Flash Player 10

弹出flash的文件选择对话框,可一次性选择多个文件。

提醒:Flash Player 10的安全机制更严格,类似打开文件上传的对话框的操作,一定需要用户交互才触发,如果用脚本触发,会报#2176的运行时错误。因此V2.2.0版本在SWF中添加了一个可定制的Button让用户交互来打开文件对话框。

void startUpload(file_id)

指定file_id来启动该文件的上传,如果file_id被忽略了,那么默认开始上传第一个文件。

void cancelUpload(file_id, trigger_error_event)

指定file_id来退出文件的上传,从上传队列中删除该文件。

如果忽略file_id,那么默认文件上传队列中的第一个文件将被退出上传。

如果取消的文件是正在上传,那么会触发uploadError事件。

如果将可选参数trigger_error_event设置为false,那么uploadError事件不会触发。

void stopUpload()

如果当前有文件上传,那么停止上传,并且将文件还原到上传队列中。

停止了正在上传的文件,uploadError事件会被触发。如果此时没有正在上传文件,那么不会发生任何操作,不会触发任何事件。

object getStats()

获取当前状态的统计对象,具体见Stats Object

void setStats(stats_object)

Stats统计对象是可以被修改的。如果你希望在上传完毕之后修改上传成功或者上传失败的统计数目时,那么可以使用该方法。

提醒:可供修改的属性只有successful_uploads ,upload_errors,upload_cancelled,queue_errors,并且值必须是Number类型。

object getFile(file_id|index)

根据file_id或者index来获取文件队列中的文件对象。file_id是文件对象中的id属性,index是文件对象中的index属性。

传 递Number类型的参数会被认定为index,那么返回的是文件队列(所有尝试入队文件,包括因没有通过文件大小、类型检测等而触发 fileQueueError,没有成功加入文件上传队列的文件对象)数组中下标为index的文件对象。如果index不在队列数组范围内,那么返回 null。

传递非Number类型的参数会被认定为file_id,那么返回的是文件上传队列(通过文件检测,准备好进行上传的文 件)数组中id为file_id的文件对象。如果参数为空,或者没有此id的文件对象,那么返回文件等待队列中的第一个文件对象,如果第一个文件对象为 空,那么返回null。

void addPostParam(name, value)

给设置中的post_params对象添加值对,当文件上传的时候,这个值对会一同在POST中发送。

如果设置的时候,post_params中以及存在该值,那么实际上会被覆盖。

提醒:SWFUload存在Cookie bug,你可以使用此方法避免。

void removePostParam(name)

从设置中的post_params对象中删除name指定的属性,当文件上传的时候,删除的值对不会继续在POST中发送。

bool addFileParam(file_id, name, value)

为指定file_id的特定文件对象添加POST值对,如果添加的name属性已经存在,那么原值会被覆盖。

如果需要给所有文件对象添加POST值,那么可以使用设置中的post_params属性。

bool removeFileParam(file_id, name)

删除由addFileParam添加的POST值对.

如果POST设置中没有此属性,那么返回false。

void setUploadURL(url)

动态修改设置中的upload_url属性。

void setPostParams(param_object)

动态修改post_params,以前的属性全部被覆盖。param_object必须是一个JavaScript的基本对象,所有属性和值都必须是字符串类型。

void setFileTypes(types, description)

动态修改设置中的file_types 和 file_types_description,两个参数都是必须的。

void setFileSizeLimit(file_size_limit)

动态修改设置中的file_size_limit,此修改针对之后的文件大小过滤有效。file_size_limit参数接收一个单位,有效的单位有B、KB、MB、GB,默认单位是KB。

例如: 2147483648 B, 2097152, 2097152KB, 2048 MB, 2 GB

void setFileUploadLimit(file_upload_limit)

动态修改设置中的file_upload_limit,特殊值0表示无限制。

提醒:这里限制的是一个SWFUpload实例控制上传成功的文件总数。

void setFileQueueLimit(file_queue_limit)

动态修改设置中的file_queue_limit,特殊值0表示无限制。

提醒:这里限制的是文件上传队列中(入队检测通过的文件会添加到上传队列等待上传)允许排队的文件总数。

void setFilePostName(file_post_name)

动态修改设置中的file_post_name,注意在Linux环境下,FlashPlayer是忽略此设置的。

void setUseQueryString(use_query_string)

动态修改设置中的use_query_string,设置为true的时候,SWFUpload以GET形式发送数据,如果为false,那么就以POST发送数据。

void setDebugEnabled(debug_enabled)

启动/禁止 debug输出,debug_enabled参数是一个布尔值。

void setButtonImageURL(url)

动态修改按钮的图片。url参数是相对于该swf文件或者是绝对地址的图片(或者是SWF)。所有FLASH支持的图片类型都可以使用(gif,jpg,png,或者是一个SWF)。

该按钮图片需要经过一定规则(CSS Sprite)的处理。按钮图片中需要包括按钮的4个状态,从上到下依次是normal, hover, down/click, disabled.(可以参照官方demo中的图片)

void setButtonDimensions(width, height)

动态修改SWF影片的尺寸以适应Button的图片大小。

void setButtonText(text)

动态设置Flash Button中显示的文字,支持HTML。HTML文本的样式可以通过CSS选择器并配合setButtonTextStyle方法来设置。关于Flash文本对HTML的支持详细可见 Adobe's Flash documentation

void setButtonTextStyle(css_style_text)

配合setButtonText方法,可以通过CSS样式来动态设置Flash Button中的文字样式。关于Flash文本对CSS的支持详细可见Adobe's Flash documentation

void setButtonTextPadding(left, top)

Sets the top and left padding of the Flash button text. The values may be negative.

void setButtonDisabled(isDisabled)

When 'true' changes the Flash Button state to disabled and ignores any clicks.

void setButtonAction(buttonAction)

Sets the action taken when the Flash button is clicked. Valid action values are taken from the BUTTON_ACTION constants.

void setButtonCursor(buttonCursor)

Sets the mouse cursor shown when hovering over the Flash button. Valid cursor values are taken from the BUTTON_CURSOR constants.

事件

SWFUpload在操作过程中会触发一系列事件,开发者可以利用这些回调的处理事件来控制UI,控制操作或者报告错误。

所有的事件都是在SWFUpload实例的上下文中调用的,因此在这些回调的事件中使用this能够直接访问到该触发该事件的实例对象。

所有事件应该在实例初始化时setting参数中预设完成。

flashReady()

该事件函数是内部事件,因此不能被重写。当SWFupload实例化,加载的FLASH完成所有初始化操作时触发此事件。

提醒:对应设置中的自定义事件swfupload_loaded_handler

swfUploadLoaded()

V2.1.0版本中已经删除了此事件

fileDialogStart()

此事件在selectFile或者selectFiles调用后,文件选择对话框显示之前触发。只能同时存在一个文件对话框。

提醒:对应设置中的自定义事件file_dialog_start_handler

fileQueued(file object)

当文件选择对话框关闭消失时,如果选择的文件成功加入上传队列,那么针对每个成功加入的文件都会触发一次该事件(N个文件成功加入队列,就触发N次此事件)。

提醒:对应设置中的自定义事件file_queued_handler

fileQueueError(file object, error code, message)

当选择文件对话框关闭消失时,如果选择的文件加入到上传队列中失败,那么针对每个出错的文件都会触发一次该事件(此事件和fileQueued事件是二选一触发,文件添加到队列只有两种可能,成功和失败)。

文件添加队列出错的原因可能有:超过了上传大小限制,文件为零字节,超过文件队列数量限制,设置之外的无效文件类型。

具体的出错原因可由error code参数来获取,error code的类型可以查看SWFUpload.QUEUE_ERROR中的定义。

提醒:对应设置中的自定义事件file_queue_error_handler

注意:如果选择入队的文件数量超出了设置中的数量限制,那么所有文件都不入队,此事件只触发一次。如果没有超出数目限制,那么会对每个文件进行文件类型和大小的检测,对于不通过的文件触发此事件,通过的文件成功入队。

fileDialogComplete(number of files selected, number of files queued)

当选择文件对话框关闭,并且所有选择文件已经处理完成(加入上传队列成功或者失败)时,此事件被触发,number of files selected是选择的文件数目,number of files queued是此次选择的文件中成功加入队列的文件数目。

提醒:对应设置中的自定义事件file_dialog_complete_handler

注意:如果你希望文件在选择以后自动上传,那么在这个事件中调用this.startUpload() 是一个不错的选择。 如果需要更严格的判断,在调用上传之前,可以对入队文件的个数做一个判断,如果大于0,那么可以开始上传。

uploadStart(file object)

在文件往服务端上传之前触发此事件,可以在这里完成上传前的最后验证以及其他你需要的操作,例如添加、修改、删除post数据等。

在完成最后的操作以后,如果函数返回false,那么这个上传不会被启动,并且触发uploadError事件(code为ERROR_CODE_FILE_VALIDATION_FAILED),如果返回true或者无返回,那么将正式启动上传。

提醒:对应设置中的自定义事件upload_start_handler

uploadProgress(file object, bytes complete, total bytes)

该事件由flash定时触发,提供三个参数分别访问上传文件对象、已上传的字节数,总共的字节数。因此可以在这个事件中来定时更新页面中的UI元素,以达到及时显示上传进度的效果。

注意: 在Linux下,Flash Player只在所有文件上传完毕以后才触发一次该事件,官方指出这是Linux Flash Player的一个bug,目前SWFpload库无法解决(我没有测试过)

提醒:对应设置中的自定义事件upload_progress_handler

uploadError(file object, error code, message)

无论什么时候,只要上传被终止或者没有成功完成,那么该事件都将被触发。error code参数表示了当前错误的类型,更具体的错误类型可以参见SWFUpload.UPLOAD_ERROR中的定义。Message参数表示的是错误的描述。File参数表示的是上传失败的文件对象。

例 如,我们请求一个服务端的一个不存在的文件处理页面,那么error code会是-200,message会是404。 停止、退出、uploadStart返回false、HTTP错误、IO错误、文件上传数目超过限制等,都将触发该事件,Upload error will not fire for files that are cancelled but still waiting in the queue。(对于官方的这句话我还存在疑问,文件退出以后怎么还会保留在文件上传队列中保留呢?)

提醒:对应设置中的自定义事件upload_error_handler

注意:此时文件上传的周期还没有结束,不能在这里开始下一个文件的上传。

uploadSuccess(file object, server data)

当文件上传的处理已经完成(这里的完成只是指向目标处理程序发送了Files信息,只管发,不管是否成功接收),并且服务端返回了200的HTTP状态时,触发此事件。

提醒:对应设置中的自定义事件upload_success_handler

注意:

  1. server data是服务端处理程序返回的数据。
  2. 此时文件上传的周期还没有结束,不能在这里开始下一个文件的上传。
  3. 在window平台下,那么服务端的处理程序在处理完文件存储以后,必须返回一个非空值,否则此事件不会被触发,随后的uploadComplete事件也无法执行。

uploadComplete(file object)

当上传队列中的一个文件完成了一个上传周期,无论是成功(uoloadSuccess触发)还是失败(uploadError触发),此事件都会被触发,这也标志着一个文件的上传完成,可以进行下一个文件的上传了。

如果要进行多文件自动上传,那么在这个时候调用this.startUpload()来启动下一个文件的上传是不错的选择。

提醒:对应设置中的自定义事件upload_complete_handler

注意:当 在进行多文件上传的时候,中途用cancelUpload取消了正在上传的文件,或者用stopUpload停止了正在上传的文件,那么在 uploadComplete中就要很小心的使用this. startUpload(),因为在上述情况下,uploadError和uploadComplete会顺序执行,因此虽然停止了当前文件的上传,但会 立即进行下一个文件的上传,你可能会觉得这很奇怪,但事实上程序并没有错。如果你希望终止整个队列的自动上传,那么你需要做额外的程序处理了。

debug(message)

如果debug setting设置为true,那么页面底部会自动添加一个textArea, SWFUpload库和Flash都会调用此事件来在页面底部的输出框中添加debug信息供调试使用。

提醒:对应设置中的自定义事件debug_handler

SWFUpload功能对象

Settings object

它是一个Object类型的变量,为SWFUpload的实例初始化提供配置。 其中的每一个配置属性都只能出现一次。 很多属性都是可选的,如果可选属性没有被配置,那么会使用SWFUpload库中默认指定的合适的值,具体可查看setting的详细介绍。

例如:(setting可以配置的所有属性)

{ upload_url : "http://www.swfupload.org/upload.php", flash_url : "http://www.swfupload.org/swfupload.swf", file_post_name : "Filedata", post_params : { "post_param_name_1" : "post_param_value_1", "post_param_name_2" : "post_param_value_2", "post_param_name_n" : "post_param_value_n" }, use_query_string : false, requeue_on_error : false, http_success : [201, 202], file_types : "*.jpg;*.gif", file_types_description: "Web Image Files", file_size_limit : "1024", file_upload_limit : 10, file_queue_limit : 2, debug : false, prevent_swf_caching : false, button_placeholder_id : "element_id", button_image_url : "http://www.swfupload.org/button_sprite.png", button_width : 61, button_height : 22, button_text : "<b>Click</b> <span class="redText">here</span>", button_text_style : ".redText { color: #FF0000; }", button_text_left_padding : 3, button_text_top_padding : 2, button_action : SWFUpload.BUTTON_ACTION.Select_FILES, button_disable : false, button_cursor : SWFUpload.BUTTON_CURSOR.HAND, button_window_mode : SWFUpload.WINDOW_MODE.TRANSPARENT, swfupload_loaded_handler : swfupload_loaded_function, file_dialog_start_handler : file_dialog_start_function, file_queued_handler : file_queued_function, file_queue_error_handler : file_queue_error_function, file_dialog_complete_handler : file_dialog_complete_function, upload_start_handler : upload_start_function, upload_progress_handler : upload_progress_function, upload_error_handler : upload_error_function, upload_success_handler : upload_success_function, upload_complete_handler : upload_complete_function, debug_handler : debug_function, custom_settings : { custom_setting_1 : "custom_setting_value_1", custom_setting_2 : "custom_setting_value_2", custom_setting_n : "custom_setting_value_n", } }

Settings 描述

upload_url

默认值:空字符串

upload_url设置接收的是一个绝对的或者相对于SWF文件的完整URL。推荐使用完整的绝对路径,以避免由浏览器和FlashPlayer修改了基准路径设置而造成的请求路径错误。

注意:这里需要考虑FlashPlayer的安全域模型。

file_post_name

默认值:Filedata

该参数设置了POST信息中上传文件的name值(类似传统Form中设置了<input type="file" name="uploadImg"/>的name属性)。

注意:在Linux下面此参数设置无效,接收的name总为Filedata,因此为了保证最大的兼容性,建议此参数使用默认值。

post_params

默认值:空的Object对象

post_params定义的是一个包含值对的object类型数据,每个文件上传的时候,其中的值对都会被一同发送到服务端。

注意:设置值对的时候,值只能是字符串或者数字。
use_query_string

默认值:false

该属性可选值为true和false,设置post_params是否以GET方式发送。如果为false,那么则以POST形式发送。

requeue_on_error

默认值:false

该属性可选值为true和false。如果设置为true,当文件对象发生uploadError时(除开fileQueue错误和 FILE_CANCELLED错误),该文件对象会被重新插入到文件上传队列的前端,而不是被丢弃。如果需要,重新入队的文件可以被再次上传。如果要从上 传队列中删除该文件对象,那么必须使用cancelUpload方法。

跟上传失败关联的所有事件同样会被一一触发,因此将上传失败的文件重新入队可能会和Queue Plugin造成冲突(或者是自动上传整个文件队列的自定义代码)。如果代码中调用了startUpload方法自动进行下一个文件的上传,同时也没有采 取任何措施让上传失败的文件退出上传队列,那么这个重新入队的上传失败的文件又会开始上传,然后又会失败,重新入队,重新上传…,进入了无止境的循 环。

该设置是在v2.1.0中引入的。

http_success

默认值:[]

该数组可自定义触发success事件的HTTP状态值。200的状态值始终会触发success,并且只有200的状态会提供serverData。

当接受一个200以外的HTTP状态值时,服务端不需要返回内容。

file_types

默认值:*.*

设置文件选择对话框的文件类型过滤规则,该属性接收的是以分号分隔的文件类型扩展名,例如“ *.jpg;*.gif”,则只允许用户在文件选择对话框中可见并可选jpg和gif类型的文件。默认接收所有类型的文件。

提醒:该设置只是针对客户端浏览器的过滤,对服务端的文件处理中的文件类型过滤没有任何限制,如果你需要做严格的文件过滤,那么服务端同样需要程序检测。

file_types_description

默认值:All Files

设置文件选择对话框中显示给用户的文件描述。

file_size_limit

默认值:0

设置文件选择对话框的文件大小过滤规则,该属性可接收一个带单位的数值,可用的单位有B,KB,MB,GB。如果忽略了单位,那么默认使用KB。特殊值0表示文件大小无限制。

提醒:该设置只对客户端的浏览器有效,对服务端的文件处理没有任何限制,如果你需要做严格文件过滤,那么服务端同样需要程序处理。

file_upload_limit

默认值:0

设置SWFUpload实例允许上传的最多文件数量,同时也是设置对象中file_queue_limit属性的上限。一旦用户已经上传成功或者添加文件 到队列达到上最大数量,那么就不能继续添加文件了。特殊值0表示允许上传的数量无限制。只有上传成功(上传触发了uploadSuccess事件)的文件 才会在上传数量限制中记数。使用setStats方法可以修改成功上传的文件数量。

注意:该值不能跨页面使用,当页面刷新以后该值也被重置。严格的文件上传数量限制应该由服务端来检测、管理。

file_queue_limit

默认值:0

设置文件上传队列中等待文件的最大数量限制。当一个文件被成功上传,出错,或者被退出上传时,如果文件队列中文件数量还没有达到上限,那么可以继续添加新 的文件入队,以顶替该文件在文件上传队列中的位置。如果允许上传的文件上限(file_upload_limit)或者剩余的允许文件上传数量小于文件队 列上限(file_queue_limit),那么该值将采用这个更小的值。

flash_url

默认值:空字符串

设置绝对或者相对于此上传页面的完整URL,一旦SWFupload实例化以后,此设置不能再被修改。

提醒:测试发现使用setUploadURL方法是可以修改此设置的。

flash_width

固定值:1px

(v2.1.0已删除) 设置插入flash影片的HTML元素容器的宽度。如果此设置小于1像素,一些浏览器会出现功能异常。 因此该值在v2.1.0中删除了自定义设置,默认设置为1像素了。

flash_height

固定值:1px

(v2.1.0已删除) 设置插入flash影片的HTML元素容器的高度。如果此设置小于1像素,一些浏览器会出现功能异常。 因此该值在v2.1.0中删除了自定义设置,默认设置为1像素了。

flash_color

默认值:#FFFFFF

(v2.2.0已删除) 设置HTML页面中的flash背景色,默认为#FFFFFF

prevent_swf_caching

默认值:true

(v2.2.0新增)该布尔值设置是否在Flash URL后添加一个随机值,用来防止浏览器缓存了该SWF影片。这是为了解决一些基于IE-engine的浏览器上的出现一个BUG。

提醒:SWFUpload是直接在flash_url后添加了一个swfuploadrnd的随机参数。如果你给定的flash_url中已经存在了GET类型的参数,那么就会出现两个问号连接符导致错误。

debug

默认值:false

该值是布尔类型,设置debug事件是否被触发。

注意:SWFUpload 代码中是将此变量和字符串true做的恒等判断,因此它只认定true为DEBUG模式开启,如果设置为1,虽然JS认定是开启模式,并且在初始化完毕后 会有生成Debug Console,但后续操作中FLASH不会输出调试信息。(因为我习惯用1和0代表布尔变量,因此一度疑惑为何Flash的debug信息无法输出。)

button_placeholder_id

默认值:null

(v2.2.0新增) 该必要参数指定了swfupload.swf将要替换的页面内的DOM元素的ID值。当对应的DOM元素被替换为SWF元素时,SWF的容器会被添加一个名称为"swfupload"的样式选择器供CSS自定义使用。

button_image_url

默认值:空字符串

(v2.2.0新增) V2.2.0版最大的改变就是引入了一个按钮到SWF中,利用该参数可以设置一个相对于该swf文件或者是绝对地址的图片(或者是SWF),作为按钮的UI展现。所有FLASH支持的图片类型都可以使用(gif,jpg,png,或者是一个SWF)。

该按钮图片需要经过一定规则(CSS Sprite)的处理。按钮图片中需要包括按钮的4个状态,从上到下依次是normal, hover, down/click, disabled.(可以参照官方demo中的图片)

button_width

默认值:1

(v2.2.0新增) 设置该SWF的宽度属性。

button_height

默认值:1

(v2.2.0新增)设置该SWF的高度属性(按钮图片高度的1/4)

button_text

默认值:空字符串

(v2.2.0新增) 该属性设置Flash Button中显示的文字,支持HTML。HTML文本的样式可以通过CSS选择器并配合button_text_style参数来设置。关于Flash文本对HTML的支持详细可见 Adobe's Flash documentation

button_text_style

默认值:"color: #000000; font-size: 16pt;"

(v2.2.0新增)此参数配合button_text参数,可以通过CSS样式来设置Flash Button中的文字样式。关于Flash文本对CSS的支持详细可见Adobe's Flash documentation

button_text_top_padding

默认值:0

(v2.2.0新增) 设置Flash Button上文字距离顶部的距离,可以使用负值。

button_text_left_padding

默认值:0

(v2.2.0新增) 设置Flash Button上文字距离左侧的距离,可以使用负值。

button_action

默认值:SWFUpload.BUTTON_ACTION.Select_FILES(多文件上传)

(v2.2.0新增) 设置Flash Button点击以后的动作。默认为SWFUpload.BUTTON_ACTION.Select_FILES,点击按钮将会打开多文件上传的对话框。 如果设置为SWFUpload.BUTTON_ACTION.Select_FILE,则为单文件上传。如果设置为 SWFUpload.BUTTON_ACTION.START_UPLOAD,则启动文件上传。

button_disabled

默认值:false

(v2.2.0新增) 该布尔值设置Flash Button是否是禁用状态。当它处于禁用状态的时候,点击不会执行任何操作。

button_cursor

默认值:SWFUpload.CURSOR.ARROW(箭头光标)

(v2.2.0新增) 此参数可以设置鼠标划过Flash Button时的光标状态。默认为SWFUpload.CURSOR.ARROW,如果设置为SWFUpload.CURSOR.HAND,则为手形

button_window_mode

默认值:SWFUpload.WINDOW_MODE.WINDOW

(v2.2.0新增) 此参数可以设置浏览器具体以哪种模式显示该SWF影片。

custom_settings

默认值:空的Object对象

该属性接收一个Object类型数据,可用于安全地存储与SWFUpload实例关联的自定义信息,例如属性和方法,而不用担心跟SWFUpload内部的方法和属性冲突以及版本升级的兼容。

设置完毕以后,可以通过实例的customSettings属性来访问。

var swfu = new SWFUpload({ custom_settings : { "My Setting" : "This is my setting", myothersetting : "This is my other setting", integer_setting : 100, a_dom_setting : document.getElementById("some_element_id") } }); var my_setting = swfu.customSettings["My Setting"]); swfu.customSettings["My Setting"] = "This is my new setting"; swfu.customSetting.myothersetting = "another new value"; swfu.customSetting.integer_setting += 25; swfu.customSetting["a_dom_setting"].style.visibility = "hidden";

Event Handlers

默认值:null

剩下的设置定义的是一系列事件处理的回调函数,在SWFUpload的操作过程中相应的事件会被触发。如果你需要在这些回调中进行自定义操作,那么你应该在设置中定义对应的JavaScript函数。

File Object

File Object包含了一组可用的文件属性,很多处理事件都会传递一个File Object参数来访问该文件的相关属性。

{ id : string, // SWFUpload控制的文件的id,通过指定该id可启动此文件的上传、退出上传等 index : number, // 文件在选定文件队列(包括出错、退出、排队的文件)中的索引,getFile可使用此索引 name : string, // 文件名,不包括文件的路径。 size : number, // 文件字节数 type : string, // 客户端操作系统设置的文件类型 creationdate : Date, // 文件的创建时间 modificationdate : Date, // 文件的最后修改时间 filestatus : number // 文件的当前状态,对应的状态代码可查看SWFUpload.FILE_STATUS }

Stats Object

该对象提供了上传队列的状态信息,访问实例的getStats方法可获取此对象。

该对象包括下面属性:

{ in_progress : number // 值为1或0,1表示当前有文件正在上传,0表示当前没有文件正在上传 files_queued : number // 当前上传队列中存在的文件数量 successful_uploads : number // 已经上传成功(uploadSuccess触发)的文件数量 upload_errors : number // 已经上传失败的文件数量 (不包括退出上传的文件) upload_cancelled : number // 退出上传的文件数量 queue_errors : number // 入队失败(fileQueueError触发)的文件数量 }

所有这些属性的值都可以使用setStats方法来修改,除了in_progressfiles_queued

SWFUpload 插件

With SWFUpload v2.0 several plugins have been introduced. They are provided to help with common tasks associated with implementing SWFUpload.

Currently most of the documentation for using the plugins is contained in the plugin JavaScript file.

SWFObject

The SWFObject plugin uses the SWFObject library to handle the embedding of the SWFUpload Flash Component into the page.

This plugin also provides support for Document Ready loading and Flash Version Detection. Usage details are documented in the plugin file itself.

Using this plugin can eliminate the flicker seen in the Graceful Degradation plugin and provides events for loading failure.

Flash Player 10: Because Flash Player 10 requires the SWFUpload swf to act is a button the movie must be visible in order for it to load. If the button_placeholder_id is set to an element that is hidden (visibility set to hidden or display set to none) SWFUpload will fail to load.

Graceful Degradation

This plugin has been superseded by the SWFObject plugin.

This plugin provides additional settings and logic for automatically hiding and showing page elements based on whether SWFUpload loads.

Flash Player 10: The Graceful Degradation plugin has been updated to support Flash Player 10. However, because the Flash Movie won't execute if it is hidden (inside an element with visibility set to hidden or display set to none) the movie must be loaded in a visible area of the page. This is handled automatically. However, the side affect is that the movie is executed twice. The plugin handles this but developers should be aware that this is happening. In most cases this simply means that you will see the SWFUpload initialization (if debug is enable) run twice. There is still only a single movie per instance and events are not fired twice.

SWFUpload v1.0.2 Compatibility

Creates compatibility with v1.0.2. Using this plugin you should be able to drop SWFUpload v2.0 in to a v1.0.2 page. This plugin is not supported and is only intended for users of SWFUpload v1.0.2 who wish to upgrade to v2 without recoding their pages.

Cookies

In response to the Flash Cookie Bug the Cookies Plugin automatically retrieves your browser's cookies and sends them with the upload. The are sent as POST or GET variables to the upload url.

Queue Handling

This plugin provides Queue Handling features such as entire queue uploading, entire queue cancelling and automatic starting of uploads after being queued.

Known Issues

The Flash Player and many Browsers have bugs that have a direct impact on the performance of SWFUpload. While we have worked hard to get around many issues there are some things that cannot be fix.

Cancelling in Linux

Older Flash 9 Players for Linux cause the browser to crash if an upload is cancelled. Newer Flash 9 Players behave better.

Upload Progress in Linux

The Flash Player in Linux sends a single uploadProgress event after the file has finished uploading.

Upload Progress in OS X

There have been some reports that uploadProgress events are not fired in MAC Flash Players. The specifics haven't been pinned down but be aware of the possible issue.

MIME Type

The Flash Player uploads all files with a mime type of application/octet-stream regardless of the file's actual mime type.

Maximum number of selected files

The Flash Player does not impose a maximum number of selected files. However, it builds a selected files string which does have a maximum length. The string is built using the file's name and the separator

[space]

. The total number of files selected is determined by the sum of the lengths of the file names and a prefixed and postfixed

character (2 characters) and the number of files selected minus one times 3 (for the separator string)

This limitation may vary from system to system. If a use selects too many files they will be receive a Flash Player generated warning message and will be left at the File Selection Dialog.

Proxies

The Flash Player may not properly use proxies. It does not handle authenticating proxies well (if at all) and will some-times crash.

Some anti-virus software uses a proxy to scan uploads and cause SWFUpload to believe the entire file has been uploaded. SWFUpload will fire uploadProgress events very quickly until it reaches 100% and will then seem to pause until the proxy completes uploading the file to the server.

Apache mod_security

Apache's mod_security validates POST to the server. Flash Player has implemented an edge case (there is argument as to whether it is invalid or note) POST for file uploads and so servers implementing mod_security will reject the upload. mod_security can be disabled using your .htaccess file

SSL

There have been some reports that the Flash Player cannot upload through SSL. The issue has not been pinned down but uploading over SSL may be unreliable. There especially seems to be an issue with using self-signed certificates.

Also, SSL tickets from untrusted Certificate Authorities (CA) do not work as Flash does not provide a method for accepting the certificate. It has been noted that, like the cookie bug, that Flash Player on Windows obtains its trusted CA list from Internet Explorer regardless of the browser in use.

Authentication

HTTP Authentication is not well supported by the Flash Player. Later versions of Flash Player behave better. Old version of Flash Player would crash the browser.

Prematurely terminated connections

Prematurely ending the response (such as a Response.end() in ASP.NET) can sometimes cause successful uploads to be reported as failed.

Filedata in Linux

Changing the Filedata value (file_post_name setting) is ignored in Linux Flash Player.

uploadSuccess & Server Data

The uploadSuccess will not fire if no data is returned from the server. This is especially problematic on the Mac version of the Flash Player.

Cookie issue

On Windows the Non-IE Flash Player plugin (FireFox, Opera, Safari, etc) sends the IE cookies regardless of the browser used. This breaks authentication and sessions for many server-side scripting technologies.

Developers should manually pass Session and Authentication cookie information and manually restore Sessions on the Server Side if they wish to use Sessions

The SWFUpload package contains work-around sample code for PHP and ASP.NET

ExternalInterface bugs

Flash Player does not properly escape data when communication with the browser/JavaScript. SWFUpload goes to great lengths to work-around this issue. If this bug is fixed in future Flash Players/Browsers then SWFUpload will send extra escaped data.

Server Data length bugs

Very long server data is corrupted on Mac and Linux Flash Players. Server data will be truncated, garbled, and/or repeated. We recommend keeping data returned from the server short and concise.

Avant Browser

For some users the Avant Browser does not work with SWFUpload after the Flash Control has been cached. This has been reproduced by the SWFUpload developers but the Avant Browser developers did not experience any problems.

When the page is reloaded SWFUpload loads and fires the swfupload_loaded event. However, none of the ExternalInterface callback functions are defined on the movie element. SWFUpload v2.0.2 has added checks which prevent swfupload_loaded from firing if the callback functions are not detected.

SWFUpload v2.2.0 added the prevent_swf_caching setting that attempts to work around this issue.

File Dialog & Page Changing

Leaving or reloading the current page while the File Browser Dialog window is open will cause the browser to crash (all browsers, all OSs). Most commonly this is caused by failing to cancel a click event on an <a> tag where the onclick event calls the selectFile or selectFiles function.

Long Running Upload Scripts

After Flash has uploaded the file to the webserver the upload script is executed. This script handles the file whether that means saving it, creating a thumbnail, scanning for viruses, etc. If the upload script does not return any data within 30 seconds Flash will disconnect and return an IO Error. You can prevent this by returning characters or data while the script runs (if possible). For PHP, the script continues to run and complete successfully even though Flash has terminated the connection. Any data returned by the script after Flash has disconnected is lost.

Other Mac Issues

  • Users have reported that uploading to subdomains does not work with the Mac Flash Player.
  • Users have reported that pages that redirect (HTTP Status 302) are not handled by the Mac Flash Player. Windows clients seem to handle this issue.
  • The flash documentation states that on OS early than OS X 10.3 the bytes loaded is always reported as -1. SWFUpload converts this to 0 but the total bytes will never be sent and 100% won't be reached. The UI should be updated to display 100% complete in uploadSuccess or uploadComplete events to maintain a consistent UI.
  • Some users have reported issues if there is a space character in the upload_url for the Mac Flash Player. Avoid spaces or try replacing them with + or %20.
  • Users have reported that the Flash Player for Mac adds the PORT to the HTTP_HOST server variable (e.g., http://www.example.com:80). If you are checking this variable in your server-side script be aware of the possible issue.

[C#]游戏大厅 从基础开始(5)--绕回来细说聊天室(上)

mikel阅读(881)

距离上次写大厅已经有几个月。中间工作繁忙,待学习的东西又很多,又有很多新产品的想法想实践,一直把这个坑闲置着。

直到前两天简单的树遍历枚举器-挑战一个程序员到底能多懒 装配脑袋的几个回帖给我带来一些灵感,让我又重新看看我聊天频道的实现,发现竟然有很多可以推敲重新处理的地方。

昨天上班的时候又把聊天部分整理了下,愿和大家分享。

 

 

 

 

Wiki定义的聊天室

网络聊天室通常直称聊天室,是一种人们可以在线交谈的的网络论坛,在同一聊天室的人们通过广播消息进行实时交谈。

聊天室可以建立在即时通讯软件(如MSN MessengerQQ)、P2P软件、万维网(如 Halapo, Meebo ) 等基础上,万维网方式更为普通和种类繁多,交谈的手段不局限于文本,更包括语音、视频。通常聊天室是按照房间或频道为单位的,在同一房间或频道的网人可以实时地广播和阅读公开消息。一般情况下,与其它网络论坛即时通讯不同的是,聊天室不保存聊天记录。

 

 

 

 

聊天室的基础功能定义

ChatBasic 

用户能够通过某种形式连接到服务, 发送自己的信息给同样使用该服务的多人看到,并且看到同样使用该服务的别人发送的信息。

 

 

 

 

 

聊天室的行为

一般的聊天室行为分为两种

“推” 和 “拉”

 

推聊天室

推聊天室的行为接近一个中转点,或者说是一个广播站。

ChatPush

这种聊天室简单明确。

由于根本不需要保存信息 不会存在多个线程访问的临界数据,不会涉及到锁 也就不会产生相应的性能损耗。

缺点也显而易见,它仅仅支持服务器可以直接向客户端推送的连接(比如tcp, udp) ,http这种无连接的协议无法使用。如果是临时掉线,那么在重连前的所有数据也都全都接收不到。

 

 

变形品种 点对点聊天室

ChatP2P

服务器把推送的义务转交给客户端。

这种方式对用户发送的内容控制力为0,如果不是tencent这种大牛 在伟大的社会主义初级阶段的和谐社会里 你执还意作这类点对点聊天室,建议请个好律师

 

 

另一种聊天室是

拉聊天室

ChatPull

 

大多数基于http的聊天室都是基于这种模式变形。

好处:支持无连接  支持无缝断线重连

坏处:具有公共数据 可能会引发并发冲突  可能会因为锁而降低性能。

 

参考下神奇的asp3年代我们怎么写聊天室:

 

 

1 <%@  language="VBScript" %>
2 <%
3 Response.Buffer=true ' 设 置 输 出 缓 存,用 于 显 示 不 同 页 面。
4 On error resume next ' 忽 略 程 序 出 错 部 分
5 If Request.ServerVariables("Request_Method")="GET" then
6 ' 判 断 客 户 是 以 什 么 方 式 请 求 WEB 页 面
7 '————————
8 ' 客 户 登 陆 界 面
9 '————————
10 %>
11 <form method="POST" action="http://www.cs02.com/luo40.asp">
12 <p>
13     <input type="text" name="nick" size="20" value="nick" style="background-color: rgb(192,192,192)"><br>
14     <input type="submit" value=" 进 入 聊 天 室 " name="B1" style="color: rgb(255,255,0);
15         font-size: 9pt; background-color: rgb(0,128,128)">
16     <p>
17         <input type="hidden" name="log" size="20" value="1"><br>
18     </p>
19 </form>
20 <%
21 Response.End ' 结 束 程 序 的 处 理
22 Else
23 Response.clear ' 清 空 缓 存 中 的 内 容
24 dim talk
25 If Request.Form("nick")<>"" then
26 ' 判 断 客 户 是 是 否 在 聊 天 界 面 中
27 Session("nick")=Request.Form("nick")
28 End If
29 '————————
30 '客 户 聊 天 界 面
31 '————————
32 %>
33 <form method="POST" action="http://www.cs02.com/luo40.asp" name="form1">
34 <p>
35     <%=Session("nick")%>
36     说 话:<input type="text" name="talk" size="50"><br>
37     <input type="submit" value=" 提 交 " name="B1">
38     <input type="reset" value=" 取 消 " name="B2"></p>
39 </form>
40 <a href="http://www.cs02.com/luo40.asp">离 开 </a>
41 <br>
42 <br>
43 <%
44     If Request.Form("log")<>1 then
45         If trim(Request.Form("talk"))="" then
46             ' 判 断 用 户 是 否 没 有 输 入 任 何 内 容
47             talk=Session("nick")&" 沉 默 是 金。"
48         Else
49             talk=trim(Request.Form("talk"))
50             ' 去 掉 字 符 后 的 空 格
51         End If
52 
53     Application.lock
54         Application("show5")=Application("show4")
55         Application("show4")=Application("show3")
56         Application("show3")=Application("show2")
57         Application("show2")=Application("show")
58         Application("show")="<table border='0' cellpadding='0' cellspacing='0' width='85%'><tr><td width='100%' bgcolor='#C0C0C0'></td></tr><tr><td width='100%'><font color='#0000FF'> 来 自 "&Request.ServerVariables("remote_addr")&""&Session("nick")&time&" 说:</font>"&talk&"</td></tr><tr><td width='100%' bgcolor='#C0C0C0'></td></tr></table><br>"
59     Application.UnLock
60     Response.Write Application("show5")
61     Response.Write Application("show4")
62     Response.Write Application("show3")
63     Response.Write Application("show2")
64     Response.Write Application("show")
65     End If
66 End If
67 %>
68 

 

 

 

 

我们看到了锁、原始社会的数据结构,暴力的队列实现,代码云,宗教,神秘主义与性。(女王怀孕了!谁干的?)

 

.net实现的看上去似乎很安全的代码

Code Snippet
  1.  
  2.         class ChatRoom
  3.         {
  4.             System.Collections.Queue MessageQ=new System.Collections.Queue() ;
  5.  
  6.             void Say(Object message)
  7.             {
  8.                 MessageQ.Enqueue(message);
  9.             }
  10.  
  11.             IEnumerable  ListenBy(Object user)
  12.             {
  13.                 lock (MessageQ.SyncRoot )
  14.                 {
  15.                          foreach (var o in MessageQ)
  16.                         {
  17.                             if (o.toUser == user | o.date > DateTime.Now.AddMinutes (-1) )
  18.                                 yield return o;
  19.                         
  20.                         }
  21.                         
  22.                 }
  23.             
  24.             }
  25.  
  26.         \

却暗含杀机-〉在 enqueue的时候如果queue 空间不足, 自扩张的过程是会影响枚举的

 

 

如何高性能实现"拉聊天室"而尽量做到无锁高并发?这就是下篇要讨论的。

 

 

“我拿什么来实现你 我的接口?”

 

Code Snippet
  1. namespace WayneGameSolution.Chat
  2. {
  3.     using System;
  4.     using System.Collections.Generic;
  5.     using WayneGameSolution.Membership;
  6.     using System.ServiceModel;
  7.     [ServiceContract]
  8.     public interface IChatChannel
  9.     {
  10.         /// <summary>
  11.         /// 清所有信息
  12.         /// </summary>
  13.         void Clear();
  14.         /// <summary>
  15.         /// 清所有\u-28729 ?期信息
  16.         /// </summary>
  17.         void ClearTimeouted();
  18.         /// <summary>
  19.         /// 得到用户所有未\u-29701 ?信息
  20.         /// </summary>
  21.         /// <param name="user">查信息的用户</param>
  22.         /// <returns>所有未\u-29701 ?的信息</returns>
  23.         ///
  24.         [OperationContract]
  25.         IEnumerable<IChatMessage> GetUserMessage(string user);
  26.         /// <summary>
  27.         /// 收到信息
  28.         /// </summary>
  29.         /// <param name="message">发\u-28671 ?的消息</param>
  30.         ///
  31.         [OperationContract]
  32.         void ReceiveMessage(IChatMessage message);
  33.         /// <summary>
  34.         /// \u-26479 ?\u-28589 ?ID
  35.         /// </summary>
  36.         ///
  37.  
  38.         string ID { get; }
  39.  
  40.         IDictionary<string,DateTime > LastReceivedTime { get; }
  41.  
  42.         LinkedList<IChatMessage> MessageLinkList { get; }
  43.  
  44.         string Name { get; }
  45.  
  46.         int TimeoutSecond { get; set; }
  47.  
  48.         ChannelType Type { get; }
  49.  
  50.   
  51.     }
  52.  
  53.     public enum ChannelType
  54.     {
  55.         PublicChannel,
  56.         AreaChannel,
  57.         GuildChannel,
  58.         TemporyChannel,
  59.         TeamChannel
  60.     }
  61. }
  62. namespace WayneGameSolution.Chat
  63. {
  64.     using System;
  65.     using System.Collections.Generic;
  66.     using WayneGameSolution.Membership;
  67.     using System.ServiceModel;
  68.     [ServiceContract]
  69.     public interface IChatChannel
  70.     {
  71.         /// <summary>
  72.         /// 清所有信息
  73.         /// </summary>
  74.         void Clear();
  75.         /// <summary>
  76.         /// 清所有\u-28729 ?期信息
  77.         /// </summary>
  78.         void ClearTimeouted();
  79.         /// <summary>
  80.         /// 得到用户所有未\u-29701 ?信息
  81.         /// </summary>
  82.         /// <param name="user">查信息的用户</param>
  83.         /// <returns>所有未\u-29701 ?的信息</returns>
  84.         ///

[MVC]ASP.NET MVC之JQuery 应用:表单验证

mikel阅读(814)

在这个例子中调用到了JQuery Validation 插件,让数据验证更方便快捷,有两种显示方式。

将提示信息显示在每项的后面

$("#test-form").validate({ submitHandler: function() { alert("提交成功!") } });

 

将提示信息显示在顶部信息框内

$("#test-form").validate({
                errorLabelContainer: 
"#ErrMessageBox",
                wrapper: 
"li",
                submitHandler: function() { alert(
"提交成功!") } //验证通后调用方法
            }); 
使用自定验证方法
 

// 中文字两个字节    
            JQuery.validator.addMethod("rangelength"function(value, element, param) {
                
var length = value.length;
                
for (var i = 0; i < value.length; i++) {
                    
if (value.charCodeAt(i) > 127) {
                        length
++;
                    }
                }
                
return this.optional(element) || (length >= param[0&& length <= param[1]);
            }, 
"输入的值在3-15个字节之间。");
自定验证方法的调用

 $("#password").rules("add", {
                required: 
true,
                rangelength: [
650],//调用上面定义的方法
                messages: {
                    required: 
"密码不能空。",
                    rangelength: 
"密码必须为6-50位字符之间。"
                }
            });
 

[Java]互联网网站的反爬虫策略浅析

mikel阅读(700)

因为搜索引擎的流行,网络爬虫已经成了很普及网络技术,除了专门做搜索的Google,Yahoo,微软,百度以外,几乎每个大型门户网站都有自己的搜索 引擎,大大小小叫得出来名字得就几十种,还有各种不知名的几千几万种,对于一个内容型驱动的网站来说,受到网络爬虫的光顾是不可避免的。
一些智能的搜索引擎爬虫的爬取频率比较合理,对网站资源消耗比较少,但是很多糟糕的网络爬虫,对网页爬取能力很差,经常并发几十上百个请求循环重复抓取,这种爬虫对中小型网站往往是毁灭性打击,特别是一些缺乏爬虫编写经验的程序员写出来的爬虫破坏力极强。曾经有一次我在JavaEye的 日志里面发现一个User-Agent是Java的爬虫一天之内爬取了将近100万次动态请求。这是一个用JDK标准类库编写的简单爬取网页程序,由于 JavaEye网站内部链接构成了回环导致程序陷入了死循环。对于JavaEye这种百万PV级别的网站来说,这种爬虫造成的访问压力会非常大,会导致网 站访问速度缓慢,甚至无法访问。
此外,相当数量的的网页爬虫目的是盗取目标网站的内容。比方说JavaEye网站就曾经被两个竞争对手网站爬取论坛帖子,然后在自己的论坛里面用机器人发帖,因此这种爬虫不仅仅影响网站访问速度,而且侵犯了网站的版权。
对于一个原创内容丰富,URL结构合理易于爬取的网站来说,简直就是各种爬虫的盘中大餐,很多网站的访问流量构成当中,爬虫带来的流量要远远超过 真实用户访问流量,甚至爬虫流量要高出真实流量一个数量级。像JavaEye网站虽然设置了相当严格的反爬虫策略,但是网站处理的动态请求数量仍然是真实 用户访问流量的2倍。可以肯定的说,当今互联网的网络流量至少有2/3的流量爬虫带来的。因此反爬虫是一个值得网站长期探索和解决的问题。
一、手工识别和拒绝爬虫的访问
有相当多的爬虫对网站会造成非常高的负载,因此识别爬虫的来源IP是很容易的事情。最简单的办法就是用netstat检查80端口的连接:

C代码
  1. netstat -nt | grep youhostip:80 | awk '{print $5}' | awk -F":" '{print $1}'| sort | uniq -c | sort -r -n   

这行shell可以按照80端口连接数量对来源IP进行排序,这样可以直观的判断出来网页爬虫。一般来说爬虫的并发连接非常高。
如果使用lighttpd做Web Server,那么就更简单了。lighttpd的mod_status提供了非常直观的并发连接的信息,包括每个连接的来源IP,访问的URL,连接状 态和连接时间等信息,只要检查那些处于handle-request状态的高并发IP就可以很快确定爬虫的来源IP了。
拒绝爬虫请求既可以通过内核防火墙来拒绝,也可以在web server拒绝,比方说用iptables拒绝:

C代码
  1. iptables -A INPUT -i eth0 -j Drop -p tcp –dport 80 -s 84.80.46.0/24    

直接封锁爬虫所在的C网段地址。这是因为一般爬虫都是运行在托管机房里面,可能在一个C段里面的多台服务器上面都有爬虫,而这个C段不可能是用户宽带上网,封锁C段可以很大程度上解决问题。
有些人提出一种脑残的观点,说我要惩罚这些爬虫。我专门在网页里面设计动态循环链接页面,让爬虫掉进陷阱,死循环爬不出来,其实根本用不着设置陷 阱,弱智爬虫对正常网页自己就爬不出来,这样做多此一举不说,而且会让真正的搜索引擎降低你的网页排名。而且运行一个爬虫根本不消耗什么机器资源,相反, 真正宝贵的是你的服务器CPU资源和服务器带宽,简单的拒绝掉爬虫的请求是反爬虫最有效的策略。
二、通过识别爬虫的User-Agent信息来拒绝爬虫
有很多爬虫并不会以很高的并发连接爬取,一般不容易暴露自己;有些爬虫的来源IP分布很广,很难简单的通过封锁IP段地址来解决问题;另外还有很 多各种各样的小爬虫,它们在尝试Google以外创新的搜索方式,每个爬虫每天爬取几万的网页,几十个爬虫加起来每天就能消耗掉上百万动态请求的资源,由 于每个小爬虫单独的爬取量都很低,所以你很难把它从每天海量的访问IP地址当中把它准确的挖出来。
这种情况下我们可以通过爬虫的User-Agent信息来识别。每个爬虫在爬取网页的时候,会声明自己的User-Agent信息,因此我们就可 以通过记录和分析User-Agent信息来挖掘和封锁爬虫。我们需要记录每个请求的User-Agent信息,对于Rails来说我们可以简单的在 app/controllers/application.rb里面添加一个全局的before_filter,来记录每个请求的User-Agent信 息:

Ruby代码
  1. logger.info "HTTP_USER_AGENT #{request.env["HTTP_USER_AGENT"]}"    

然后统计每天的production.log,抽取User-Agent信息,找出访问量最大的那些User-Agent。要注意的是我们只关注 那些爬虫的User-Agent信息,而不是真正浏览器User-Agent,所以还要排除掉浏览器User-Agent,要做到这一点仅仅需要一行 shell:

Ruby代码
  1. grep HTTP_USER_AGENT production.log | grep -v -E 'MSIE|Firefox|Chrome|Opera|Safari|Gecko' | sort | uniq -c | sort -r -n | head -n 100 > bot.log    

统计结果类似这样:

C代码
  1. 57335 HTTP_USER_AGENT Baiduspider+(+http://www.baidu.com/search/spider.htm)  
  2. 56639 HTTP_USER_AGENT Mozilla/5.0 (compatible; Googlebot/2.1; +http://www.google.com/bot.html)  
  3. 42610 HTTP_USER_AGENT Mediapartners-Google  
  4. 19131 HTTP_USER_AGENT msnbot/2.0b (+http://search.msn.com/msnbot.htm)  

从日志就可以直观的看出每个爬虫的请求次数。要根据User-Agent信息来封锁爬虫是件很容易的事情,lighttpd配置如下:

C代码
  1. $HTTP["useragent"] =~ "qihoobot|^Java|Commons-HttpClient|Wget|^PHP|Ruby|Python" {  
  2.   url.rewrite = ( "^/(.*)" => "/crawler.html" )  
  3. }  

使用这种方式来封锁爬虫虽然简单但是非常有效,除了封锁特定的爬虫,还可以封锁常用的编程语言和HTTP类库的User-Agent信息,这样就可以避免很多无谓的程序员用来练手的爬虫程序对网站的骚扰。
还有一种比较常见的情况,就是某个搜索引擎的爬虫对网站爬取频率过高,但是搜索引擎给网站带来了很多流量,我们并不希望简单的封锁爬虫,仅仅是希望降低爬虫的请求频率,减轻爬虫对网站造成的负载,那么我们可以这样做:

C代码
  1. $HTTP["user-agent"] =~ "Baiduspider+" {  
  2.     connection.delay-seconds = 10  
  3. }  

对百度的爬虫请求延迟10秒钟再进行处理,这样就可以有效降低爬虫对网站的负载了。
三、通过网站流量统计系统和日志分析来识别爬虫
有些爬虫喜欢修改User-Agent信息来伪装自己,把自己伪装成一个真实浏览器的User-Agent信息,让你无法有效的识别。这种情况下我们可以通过网站流量系统记录的真实用户访问IP来进行识别。
主流的网站流量统计系统不外乎两种实现策略:一种策略是在网页里面嵌入一段js,这段js会向特定的统计服务器发送请求的方式记录访问量;另一种 策略是直接分析服务器日志,来统计网站访问量。在理想的情况下,嵌入js的方式统计的网站流量应该高于分析服务器日志,这是因为用户浏览器会有缓存,不一 定每次真实用户访问都会触发服务器的处理。但实际情况是,分析服务器日志得到的网站访问量远远高于嵌入js方式,极端情况下,甚至要高出10倍以上。
现在很多网站喜欢采用awstats来分析服务器日志,来计算网站的访问量,但是当他们一旦采用Google Analytics来统计网站流量的时候,却发现GA统计的流量远远低于awstats,为什么GA和awstats统计会有这么大差异呢?罪魁祸首就是 把自己伪装成浏览器的网络爬虫。这种情况下awstats无法有效的识别了,所以awstats的统计数据会虚高。
其实作为一个网站来说,如果希望了解自己的网站真实访问量,希望精确了解网站每个频道的访问量和访问用户,应该用页面里面嵌入js的方式来开发自 己的网站流量统计系统。自己做一个网站流量统计系统是件很简单的事情,写段服务器程序响应客户段js的请求,分析和识别请求然后写日志的同时做后台的异步 统计就搞定了。
通过流量统计系统得到的用户IP基本是真实的用户访问,因为一般情况下爬虫是无法执行网页里面的js代码片段的。所以我们可以拿流量统计系统记录 的IP和服务器程序日志记录的IP地址进行比较,如果服务器日志里面某个IP发起了大量的请求,在流量统计系统里面却根本找不到,或者即使找得到,可访问 量却只有寥寥几个,那么无疑就是一个网络爬虫。
分析服务器日志统计访问最多的IP地址段一行shell就可以了:

C代码
  1. grep Processing production.log | awk '{print $4}' | awk -F'.' '{print $1"."$2"."$3".0"}' | sort | uniq -c | sort -r -n | head -n 200 > stat_ip.log    

然后把统计结果和流量统计系统记录的IP地址进行对比,排除真实用户访问IP,再排除我们希望放行的网页爬虫,比方Google,百度,微软msn爬虫等等。最后的分析结果就就得到了爬虫的IP地址了。以下代码段是个简单的实现示意:

Ruby代码
  1. whitelist = []  
  2. IO.foreach("#{RAILS_ROOT}/lib/whitelist.txt") { |line| whitelist << line.split[0].strip if line }  
  3.   
  4. realiplist = []  
  5. IO.foreach("#{RAILS_ROOT}/log/visit_ip.log") { |line|  realiplist << line.strip if line }  
  6.   
  7. iplist = []  
  8. IO.foreach("#{RAILS_ROOT}/log/stat_ip.log"do |line|  
  9.   ip = line.split[1].strip  
  10.   iplist << ip if line.split[0].to_i > 3000 && !whitelist.include?(ip) && !realiplist.include?(ip)  
  11. end   
  12.   
  13. Report.deliver_crawler(iplist)  

分析服务器日志里面请求次数超过3000次的IP地址段,排除白名单地址和真实访问IP地址,最后得到的就是爬虫IP了,然后可以发送邮件通知管理员进行相应的处理。
四、网站的实时反爬虫防火墙实现策略
通过分析日志的方式来识别网页爬虫不是一个实时的反爬虫策略。如果一个爬虫非要针对你的网站进行处心积虑的爬取,那么他可能会采用分布式爬取策 略,比方说寻找几百上千个国外的代理服务器疯狂的爬取你的网站,从而导致网站无法访问,那么你再分析日志是不可能及时解决问题的。所以必须采取实时反爬虫 策略,要能够动态的实时识别和封锁爬虫的访问。
要自己编写一个这样的实时反爬虫系统其实也很简单。比方说我们可以用memcached来做访问计数器,记录每个IP的访问频度,在单位时间之 内,如果访问频率超过一个阀值,我们就认为这个IP很可能有问题,那么我们就可以返回一个验证码页面,要求用户填写验证码。如果是爬虫的话,当然不可能填 写验证码,所以就被拒掉了,这样很简单就解决了爬虫问题。
用memcache记录每个IP访问计数,单位时间内超过阀值就让用户填写验证码,用Rails编写的示例代码如下:

Ruby代码
  1. ip_counter = Rails.cache.increment(request.remote_ip)  
  2. if !ip_counter  
  3.   Rails.cache.write(request.remote_ip, 1, :expires_in => 30.minutes)  
  4. elsif ip_counter > 2000  
  5.   render :template => 'test':status => 401 and return false  
  6. end  

这段程序只是最简单的示例,实际的代码实现我们还会添加很多判断,比方说我们可能要排除白名单IP地址段,要允许特定的User-Agent通过,要针对登录用户和非登录用户,针对有无referer地址采取不同的阀值和计数加速器等等。
此外如果分布式爬虫爬取频率过高的话,过期就允许爬虫再次访问还是会对服务器造成很大的压力,因此我们可以添加一条策略:针对要求用户填写验证码 的IP地址,如果该IP地址短时间内继续不停的请求,则判断为爬虫,加入黑名单,后续请求全部拒绝掉。为此,示例代码可以改进一下:

Ruby代码
  1. before_filter :ip_firewall:except => :test  
  2. def ip_firewall  
  3.   render :file => "#{RAILS_ROOT}/public/403.html":status => 403 if BlackList.include?(ip_sec)  
  4. end  

我们可以定义一个全局的过滤器,对所有请求进行过滤,出现在黑名单的IP地址一律拒绝。对非黑名单的IP地址再进行计数和统计:

Ruby代码
  1. ip_counter = Rails.cache.increment(request.remote_ip)  
  2. if !ip_counter  
  3.   Rails.cache.write(request.remote_ip, 1, :expires_in => 30.minutes)  
  4. elsif ip_counter > 2000  
  5.   crawler_counter = Rails.cache.increment("crawler/#{request.remote_ip}")  
  6.   if !crawler_counter  
  7.     Rails.cache.write("crawler/#{request.remote_ip}", 1, :expires_in => 10.minutes)  
  8.   elsif crawler_counter > 50  
  9.     BlackList.add(ip_sec)  
  10.     render :file => "#{RAILS_ROOT}/public/403.html":status => 403 and return false  
  11.   end  
  12.   render :template => 'test':status => 401 and return false  
  13. end  

如果某个IP地址单位时间内访问频率超过阀值,再增加一个计数器,跟踪他会不会立刻填写验证码,如果他不填写验证码,在短时间内还是高频率访问, 就把这个IP地址段加入黑名单,除非用户填写验证码激活,否则所有请求全部拒绝。这样我们就可以通过在程序里面维护黑名单的方式来动态的跟踪爬虫的情况, 甚至我们可以自己写个后台来手工管理黑名单列表,了解网站爬虫的情况。
这个策略已经比较智能了,但是还不够好!我们还可以继续改进:
1、用网站流量统计系统来改进实时反爬虫系统
还记得吗?网站流量统计系统记录的IP地址是真实用户访问IP,所以我们在网站流量统计系统里面也去操作memcached,但是这次不是增加计 数值,而是减少计数值。在网站流量统计系统里面每接收到一个IP请求,就相应的cache.decrement(key)。所以对于真实用户的IP来说, 它的计数值总是加1然后就减1,不可能很高。这样我们就可以大大降低判断爬虫的阀值,可以更加快速准确的识别和拒绝掉爬虫。
2、用时间窗口来改进实时反爬虫系统
爬虫爬取网页的频率都是比较固定的,不像人去访问网页,中间的间隔时间比较无规则,所以我们可以给每个IP地址建立一个时间窗口,记录IP地址最 近12次访问时间,每记录一次就滑动一次窗口,比较最近访问时间和当前时间,如果间隔时间很长判断不是爬虫,清除时间窗口,如果间隔不长,就回溯计算指定 时间段的访问频率,如果访问频率超过阀值,就转向验证码页面让用户填写验证码。
最终这个实时反爬虫系统就相当完善了,它可以很快的识别并且自动封锁爬虫的访问,保护网站的正常访问。不过有些爬虫可能相当狡猾,它也许会通过大 量的爬虫测试来试探出来你的访问阀值,以低于阀值的爬取速度抓取你的网页,因此我们还需要辅助第3种办法,用日志来做后期的分析和识别,就算爬虫爬的再 慢,它累计一天的爬取量也会超过你的阀值被你日志分析程序识别出来。
总之我们综合运用上面的四种反爬虫策略,可以很大程度上缓解爬虫对网站造成的负面影响,保证网站的正常访问。

[C#]使用接口实现附带插件功能的程序

mikel阅读(677)

插件功能给软件的使用者可以扩充软件功能的机会。我们不可能让软件适用于所有人,也不是所有的人都会出资帮助你实现他们的需求。插件功能提供了一个软件的高度可扩充性,允许用户作为软件的二次开发者,继续完善软件的功能。

为了在软件中加入插件功能,我们需要下面几个特别的条件:

(1)      本软件(此后我们称之为‘宿主程序’)需要开放自己的成员,包括属性、方法、事件为插件程序提供服务。

(2)      宿主程序要很好的隐藏一些信息,阻止插件程序有意或无意的破坏本身的功能。

(3)      宿主程序提供插件服务,方便插件功能的升级。

(4)      定义一个统一的标志信息,保证宿主程序可以正常的识别并运行插件程序而不会出现类型安全问题。

为此我们模仿Visual Studio .Net本身提供的Addin的实现机制来实现我们的插件程序。

attachments/month_200701/8894356039.jpg

第一步,制作接口。它是建立在宿主程序和插件之间的桥梁。

首先我们建立一个“插件标识”接口,这个接口用来标识我们的插件类的特性。

Public Interface IPlugins

    Sub Connect(ByVal PluginsApp As IPluginsApplication)

End Interface

这个接口里面我们定义了一个方法Connect,用来启动我们的插件程序。也就是说,我们的宿主程序将会统一使用Connect方法启动插件程序。而对于插件程序,入口地址将是Connect方法。这个有点类似于普通应用程序的Main函数。Connect函数的参数IPluginsApplication表示我们宿主程序的实例,稍后将会进一步解释。

其次,我们建立一个“插件服务”接口,这个接口将宿主程序需要开放的属性、方法、实现定义出来,通过接口的方式提供给插件程序。

Public Interface IPluginsApplication

    Event Display(ByVal sender As Object, ByVal e As EventArgs)

    Property Caption() As String

    Sub DisplayInput(ByVal TextAs String)

End Interface

在例子中我们简单定义了一个事件、一个属性和一个方法。插件程序在开发的时候只要引用了我们的“插件服务”接口就可以调用里面定义的内容了。

 

第二步,建立宿主程序。

但是光有接口是不能执行里面的内容的,必须要有一个实现了这个接口的实例才可以。这里我们让宿主程序实现这个接口,并且实现这些接口里面的内容,让插件程序可以进行操作。

Public Class Form1

    Implements PluginsInterface.IPluginsApplication

    Public Event Display(ByVal sender As Object, ByVal e As System.EventArgs) Implements PluginsInterface.IPluginsApplication.Display

    Public Property Caption() As String Implements PluginsInterface.IPluginsApplication.Caption

        Get

            Return Me.Text

        End Get

        Set(ByVal value As String)

            Me.Text = value

        End Set

    End Property

    Public Sub DisplayInput(ByVal Text As String) Implements PluginsInterface.IPluginsApplication.DisplayInput

        MsgBox("输入内容:" & Text)

    End Sub

    Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

        RaiseEvent Display(Me, New EventArgs)

        Me.DisplayInput(Me.TextBox1.Text)

    End Sub

End Class

我们用一个标准的Windows窗体来实现“插件服务”接口的内容。通过Caption属性可以更改窗体的标题,通过DisplayInput方法可以显示字符串。

这样我们的宿主程序由于实现了“插件服务”接口,就可以通过“插件服务”接口来将实例传递进插件程序。我们回到“插件标识”接口的Connect方法,插件的入口函数参数将宿主程序通过“插件服务”接口的实例传递到插件程序内,使得插件程序可以调用宿主程序开放的内容。而且由于通过接口传递,这些操作都是类型安全的。

 

第三步,寻找并启动插件。

插件程序将会以动态链接库的形式提供,这就需要我们的宿主程序找到插件程序的文件,判断是不是合法的插件,实例化并且启动。

首先我们必须定义一个插件存放的路径,比如运行目录下面的Plugins目录。然后寻找这一目录下面所有的dll文件进行判断。这里我们固定好路径和文件名。

对于找到的文件,通过反射我们就可以得到定义于这个dll文件中的所有类定义信息。通过刚才我们说的“插件标识”接口逐个判断,将实现了“插件标识”接口的类作为我们判断合法的插件类。然后使用实例化方法进行实例化。(注意,我们的插件程序默认一个无参数的实例化方法。)通过强制类型转换,将这个Object的实例转化为我们的“插件标识”接口实例,也就是IPlugins。由于此前我们已经判断过了,这个类实现了“插件标识”接口(也就是IPlugins接口),所以这个转换是安全的。最后通过IPluginsConnect方法启动接口程序,将宿主程序,也就是我们的窗体实例通过参数传递。(由于我们的窗体已经实现了接口IPluginsApplication,所以这步操作也是安全的。)此后,程序将由插件接管,对于宿主程序,插件和宿主自己同时进行操作。

    Dim pobj As PluginsInterface.IPlugins

    Private Sub Button2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click

        Dim ass As Reflection.Assembly = Reflection.Assembly.LoadFile("E:\Visual Sutdio Project 2005\PluginsApplication\Plugins\bin\Debug\Plugins.dll")

        Dim t As Type = Nothing

        For Each t In ass.GetTypes

            If t.IsClass AndAlso t.GetInterface(GetType(PluginsInterface.IPlugins).FullName, True) IsNot Nothing Then

                Exit For

            End If

        Next

        If t IsNot Nothing Then

            pobj = ass.CreateInstance(t.FullName, True)

            pobj.Connect(Me)

        End If

    End Sub

 

第四步,制作插件。

将一个类实现“插件标识”接口,用来表示这个类是宿主程序可识别的插件。同时必须实现Connect方法。通过Connect的参数,插件程序可以使用宿主程序通过“插件服务”接口提供的功能。

Public Class Plugins1

    Implements PluginsInterface.IPlugins

    Private WithEvents m_papp As PluginsInterface.IPluginsApplication

    Public Sub Connect(ByVal PluginsApp As PluginsInterface.IPluginsApplication) Implements PluginsInterface.IPlugins.Connect

        MsgBox("插件启动成功。")

        Me.m_papp = PluginsApp

        Me.m_papp.Caption = InputBox("请输入宿主程序的窗体标题")

        Me.m_papp.DisplayInput(InputBox("请输入字符串"))

    End Sub

    Private Sub m_papp_Display(ByVal sender As Object, ByVal e As System.EventArgs) Handles m_papp.Display

        Dim f As New Form1

        f.ShowDialog()

    End Sub

End Class

 

通过上述方法,我们就制作完成了一个简单的插件。

总结一下:

(1)      通过接口定义插件的标识,进行类型验证并启动插件程序。这样做的好处是统一了插件的类型并且可以安全的进行启动。

(2)      通过接口定义宿主程序希望公开的功能。这样做一方面保证了宿主程序不会被插件程序完全的控制,另一方面让插件程序可以安全的运行宿主提供的方法。缺点是宿主程序如果有多层嵌套的类关系需要开放的话,需要将所有的类都重新通过接口进行封装。

(3)      宿主程序、插件程序引用统一的接口程序,将插件的开发了宿主程序本身脱离,提高宿主的安全性,并且防止了循环引用的发生。

PS:本文所用到的程序代码下载文件pluginsapplication.zip