武眉博<活靶子.Net>
<Marble:blog runat="server"/>
FckEditor,远程图片下载,插件
有时候我们从其他网页上拷贝来的内容中含有图片,当原始地址失效后就会影响读者阅读。
所以我制作了这样一个插件,可以将远程图片保存到本地服务器。
声明:
下面的文字是本文不可缺少的部分,转载请保留,谢谢!
////////////////////////////////////////////////////
作者:武眉博<活靶子.NET>
同时首发于:
落伍者
&&
博客园
开发者学院
&&
.Net男孩社区
////////////////////////////////////////////////////
今天转载了
xiaozhuang
朋友的文章同时从博客园服务器上下载了图片
演示见:
http://www.devedu.com/Doc/DotNet/AspNet/AspNet-AjaxWCF-ServiceADONET-Entity-FrameworkShiXianShuJuLieBiaoShuJuShaiXuanFenYePaiXuShanChu.aspx
原理如下:
1.实现ICallbackEventHandler接口以用启用客户端回调。
2.从当前FckEdiotr内容分析出所有<img标签,取得src的地址。
3.回调下载到服务器。
4.返回下载后位于本服务器上的路径。
5.替换当前FckEdiotr内容内对应的<img标签的src属性。
其他废话不多说了,代码中都有注释。
如果您熟悉Fckeditor的插件工作流程,请继续向下阅读,另请不要留言要我直接提供下载,下面的代码已经可以完整调试了。
E:\IISROOT\FckTest\FckTest\fckeditor\editor\plugins\remoteimagerubber\
remoteimagerubber.aspx
1
<%
--
2
使用单页模型(非代码后置),是为了便于此插件部署,
3
不需编译成dll,只需拷贝remoteimagerubber.aspx 和 fckplugin.js 到plugn目录,
4
并配置一下fckconfig.js及相应的语言包,就可以使用了。
5
--
%>
6
7
<%
@ Page Language
=
"
C#
"
%>
8
9
<%
@ Import Namespace
=
"
System.Net
"
%>
10
<%
--
11
实现ICallbackEventHandler接口以提供客户端回调功能。
12
--
%>
13
<%
@ Implements Interface
=
"
System.Web.UI.ICallbackEventHandler
"
%>
14
15
<
script
runat
="server"
>
16
17
//
/ <summary>
18
//
/ 此处配置远程文件保存目录
19
//
/ </summary>
20
private static readonly string savePath
=
"
~/Uploads/
"
;
21
22
//
/ <summary>
23
//
/ 此处配置允许下载的文件扩展名
24
//
/ <remarks>
25
//
/ 暂未考虑使用动态网页输出的图片如:http://site/image.aspx?uid=00001 这样的URI;
26
//
/ 若要实现此功能可读取流并判断ContentType,将流另存为相应文件格式即可。
27
//
/ </remarks>
28
//
/ </summary>
29
private static readonly string[ ] allowImageExtension
=
new
string[ ] {
"
.jpg
"
,
"
.png
"
,
"
.gif
"
};
30
31
//
/ <summary>
32
//
/ 此处配置本地(网站)主机名
33
//
/ </summary>
34
private static readonly string[ ] localhost
=
new
string[ ] {
"
localhost
"
,
"
www.devedu.com
"
};
35
36
private string localImageSrc
=
string.Empty;
37
38
private
void
Page_Load( object obj , EventArgs args )
39
{
40
if
(
!
Page.IsPostBack )
41
{
42
ClientScriptManager csm
=
Page.ClientScript;
43
44
string scripCallServerDownLoad
=
csm.GetCallbackEventReference(
this
,
"
args
"
,
"
__ReceiveServerData
"
,
"
context
"
);
45
string callbackScriptDwonLoad
=
"
function __CallServerDownLoad(args , context) {
"
+
scripCallServerDownLoad
+
"
; }
"
;
46
if
(
!
csm.IsClientScriptBlockRegistered(
"
__CallServerDownLoad
"
) )
47
{
48
csm.RegisterClientScriptBlock(
this
.GetType( ) ,
"
__CallServerDownLoad
"
, callbackScriptDwonLoad ,
true
);
49
}
50
}
51
}
52
53
#region ICallbackEventHandler 成员
54
55
//
/ <summary>
56
//
/ 返回数据
57
//
/ </summary>
58
//
/ <remarks>如果处理过程中出现错误,则仍然返回远程路径</remarks>
59
//
/ <returns>服务器端处理后的本地图片路径</returns>
60
public string GetCallbackResult( )
61
{
62
return
localImageSrc;
63
64
}
65
66
//
/ <summary>
67
//
/ 处理回调事件
68
//
/ </summary>
69
//
/ <param name="eventArgument">一个字符串,表示要传递到事件处理程序的事件参数</param>
70
public
void
RaiseCallbackEvent( string eventArgument )
71
{
72
73
string remoteImageSrc
=
eventArgument;
74
75
string fileName
=
remoteImageSrc.Substring( remoteImageSrc.LastIndexOf(
"
/
"
)
+
1
);
76
string ext
=
System.IO.Path.GetExtension( fileName );
77
78
if
(
!
IsAllowedDownloadFile( ext ) )
79
{
80
//
非指定类型图片不进行下载,直接返回原地址。
81
localImageSrc
=
remoteImageSrc;
82
return
;
83
}
84
85
Uri uri
=
new
Uri( remoteImageSrc );
86
if
( IsLocalSource( uri ) )
87
{
88
//
本地(本网站下)图片不进行下载,直接返回原地址。
89
localImageSrc
=
remoteImageSrc;
90
return
;
91
}
92
93
try
94
{
95
//
自动创建一个目录。
96
DateTime now
=
DateTime.Now;
97
string datePath
=
string.Format( @
"
{0}\{1}\{2}\{3}
"
, now.Year , now.Month.ToString(
"
00
"
) , now.Day.ToString(
"
00
"
) , Guid.NewGuid( ).ToString( ) );
98
99
string localDirectory
=
System.IO.Path.Combine( Server.MapPath( savePath ) , datePath );
100
if
(
!
System.IO.Directory.Exists( localDirectory ) )
101
{
102
System.IO.Directory.CreateDirectory( localDirectory );
103
}
104
105
string localFilePath
=
System.IO.Path.Combine( localDirectory , fileName );
106
107
//
不存在同名文件则开始下载,若已经存在则不下载该文件,直接返回已有文件路径。
108
if
(
!
System.IO.File.Exists( localFilePath ) )
109
{
110
Client.DownloadFile( uri , localFilePath );
111
}
112
113
string localImageSrc
=
ResolveUrl(
"
~/
"
+
localFilePath.Replace( Server.MapPath(
"
~/
"
) , string.Empty ).Replace(
"
\\
"
,
"
/
"
) );
114
115
}
116
catch
117
{
118
//
下载过程中出现任何异常都不抛出( 有点狠啊 :) ),仍然用远程图片链接。
119
localImageSrc
=
remoteImageSrc;
120
}
121
122
}
123
124
125
#endregion
126
127
private WebClient client;
128
129
//
/ <summary>
130
//
/ <see cref="System.Net.WebClient"/>
131
//
/ </summary>
132
public WebClient Client
133
{
134
get
135
{
136
if
( client
!=
null
)
137
{
138
return
client;
139
}
140
141
client
=
new
WebClient( );
142
client.Headers.Add(
"
user-agent
"
,
"
Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2;)
"
);
143
144
return
client;
145
146
}
147
}
148
149
//
/ <summary>
150
//
/ 判断Uri是否为本地路径
151
//
/ </summary>
152
//
/ <param name="uri"></param>
153
//
/ <returns></returns>
154
private bool IsLocalSource( Uri uri )
155
{
156
for
(
int
i
=
localhost.Length ;
--
i
>=
0
; )
157
{
158
if
( localhost[ i ].ToLower( )
==
uri.Host.ToLower( ) )
159
{
160
return
true
;
161
}
162
}
163
164
return
false
;
165
166
}
167
168
//
/ <summary>
169
//
/ 检测文件类型是否为允许下载的文件类型
170
//
/ </summary>
171
//
/ <param name="extension">扩展名 eg: ".jpg"</param>
172
//
/ <returns></returns>
173
private bool IsAllowedDownloadFile( string extension )
174
{
175
for
(
int
i
=
allowImageExtension.Length ;
--
i
>=
0
; )
176
{
177
if
( allowImageExtension[ i ].ToLower( )
==
extension.ToLower( ) )
178
{
179
return
true
;
180
}
181
}
182
183
return
false
;
184
}
185
186
</
script
>
187
188
<!
DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"
>
189
<
html
xmlns
="http://www.w3.org/1999/xhtml"
>
190
<
head
runat
="server"
>
191
<
title
></
title
>
192
<
style
type
="text/css"
>
193
body
{
margin
:
0px
;
overflow
:
hidden
;
background-color
:
buttonface
;
}
194
td
{
font-size
:
11pt
;
font-family
:
Arial
;
text-align
:
left
;
}
195
#domProgressBarId
{
196
width
:
0%
;
197
height
:
15px
;
198
border-right
:
buttonhighlight 1px solid
;
199
border-top
:
buttonshadow 1px solid
;
200
border-left
:
buttonshadow 1px solid
;
201
border-bottom
:
buttonhighlight 1px solid
;
202
background-color
:
highlight
;
203
}
204
</
style
>
205
206
<
script
type
="text/javascript"
language
="javascript"
>
207
208
var
RemoteImageRubber
=
function
( remoteSrcList )
209
{
210
this
._remoteSrcList
=
remoteSrcList;
211
this
._totalFilesCount
=
remoteSrcList.length;
212
}
213
214
RemoteImageRubber.prototype.CurrentPercent
=
function
()
215
{
216
return
Math.round(
100
*
(
1
-
this
.CurrentFilesCount()
/
this
.TotalFilesCount() ) )
+
"
%
"
;
217
}
218
219
RemoteImageRubber.prototype.TotalFilesCount
=
function
()
220
{
221
return
this
._totalFilesCount;
222
}
223
224
RemoteImageRubber.prototype.CurrentFilesCount
=
function
()
225
{
226
return
this
._remoteSrcList.length;
227
}
228
229
RemoteImageRubber.prototype.NextFile
=
function
()
230
{
231
232
if
(
this
._remoteSrcList.length
>
0
)
233
{
234
var
currentRemoteSrc
=
this
._remoteSrcList.shift( )
235
__PreCallServer(currentRemoteSrc);
236
}
237
}
238
239
</
script
>
240
241
<
script
type
="text/javascript"
language
="javascript"
>
242
243
var
oEditor;
244
var
domProgressBar;
245
var
domCurrentFile;
246
var
domAllFilesCount;
247
var
domAlreadyDownloadFilesCount;
248
249
var
imageUrls;
250
var
remoteList
=
new
Array();
251
var
localList
=
new
Array();
252
253
var
progressBar;
254
255
function
Ok()
256
{
257
var
__imgIndex;
258
for
(__imgIndex
=
0
; __imgIndex
<
imageUrls.length; __imgIndex
++
)
259
{
260
imageUrls[__imgIndex].src
=
localList[__imgIndex];
261
}
262
263
return
true
;
264
}
265
266
</
script
>
267
268
<
script
language
="javascript"
type
="text/javascript"
>
269
270
function
__PreCallServer(currentRemoteSrc)
271
{
272
var
start
=
currentRemoteSrc.lastIndexOf(
"
/
"
)
+
1
;
273
var
end
=
currentRemoteSrc.length
-
currentRemoteSrc.lastIndexOf(
"
/
"
);
274
275
var
currentFileName
=
currentRemoteSrc.substr(start,end);
276
277
domCurrentFile.innerHTML
=
currentFileName;
278
__CallServerDownLoad(currentRemoteSrc,'');
279
280
}
281
282
function
__ReceiveServerData(receiveValue ,context)
283
{
284
//
注意:-------------------------------------------------------------------------------------------
285
//
286
//
(1)不要在接收回调数据时使用变量 "i"。
287
//
(2)如果再次回调请使用window.setTimeout(
.这样的形式
288
//
289
//
否则会导致 "'__pendingCallbacks[
].async' 为空或不是对象"的错误产生。
290
//
291
//
因为MS的开发人员在WebForm_CallbackComplete函数内使用了全局变量"i" 。这是一个比较ugly的bug。
292
//
293
//
参见:
294
//
http://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=101974
295
//
http://developers.de/blogs/damir_dobric/archive/2006/03/02/4.aspx?Ajax_CallBack=true
296
//
http://developers.de/files/folders/279/download.aspx
297
//
http://blogs.sqlxml.org/bryantlikes/archive/2005/12/20/4593.aspx
298
//
299
//
-------------------------------------------------------------------------------------------------
300
301
if
(receiveValue )
302
{
303
var
localSrc
=
receiveValue;
304
localList.push(localSrc);
305
306
domAlreadyDownloadFilesCount.innerHTML
=
progressBar.TotalFilesCount()
-
progressBar.CurrentFilesCount();
307
domProgressBar.style.width
=
progressBar.CurrentPercent();
308
309
if
( progressBar.CurrentFilesCount()
>
0
)
310
{
311
window.setTimeout(
"
progressBar.NextFile()
"
,
0
);
312
}
313
}
314
315
if
(progressBar.CurrentFilesCount()
==
0
)
316
{
317
window.setTimeout(
"
__reFlush()
"
,
500
)
318
}
319
}
320
321
function
__StartDownLoad()
322
{
323
imageUrls
=
oEditor.EditorDocument.body.getElementsByTagName(
"
img
"
);
324
325
var
m;
326
for
(m
=
0
; m
<
imageUrls.length; m
++
)
327
{
328
remoteList[m]
=
imageUrls[m].src;
329
}
330
331
progressBar
=
new
RemoteImageRubber(remoteList);
332
domAllFilesCount.innerHTML
=
progressBar.TotalFilesCount();
333
334
window.setTimeout(
"
progressBar.NextFile()
"
,
0
);
335
336
}
337
338
function
__reFlush()
339
{
340
341
domProgressBar.style.width
=
"
100%
"
;
342
343
//
display the 'OK' button
344
window.parent.SetOkButton(
true
) ;
345
}
346
347
348
</
script
>
349
350
</
head
>
351
<
body
>
352
<
form
id
="aspnetForm"
runat
="server"
>
353
<
div
style
="width: 300px; padding-left: 10px;"
>
354
<
table
border
="0"
cellspacing
="0"
cellpadding
="2"
>
355
<
tr
>
356
<
td
nowrap
="nowrap"
style
="width: 290px;"
>
357
当前文件:
<
span
id
="domCurrentFile"
style
="display: inline; text-overflow: ellipsis"
></
span
></
td
>
358
</
tr
>
359
<
tr
>
360
<
td
style
="text-align: left; width: 290px;"
>
361
<
div
id
="domProgressBarId"
>
362
</
div
>
363
</
td
>
364
</
tr
>
365
<
tr
>
366