程序二:显示目录中所有子目录和文件的程序listdir.aspx
目录下有子目录和文件两种形式,必须分别对待。我们调用此程序本身对子目录进行列表显示,而文件我们需要调用showfile.aspx程序对文件的属性和内容进行显示。并且两者还有不同的删除方法,所以我们在这里设置了两个DataGrid,两个DataTable,两个DataView,分别处理和显示目录和文件。
显示和处理目录和文件的DataGrid的代码(代码在listdir.aspx文件):
显示目录或文件的序号和名称的数据列类似于listdrivers.aspx程序中的相应代码,这里就不再重复了。对于子目录和文件分别有各自的处理页面,所以需要导航到两个不同的页面,对于子目录,我们继续使用listdir.aspx程序对其下的子目录和文件进行列表显示:
<asp:HyperLinkColumn DataNavigateUrlField="DirName" DataNavigateUrlFormatString="listdir.aspx?dir={0}" DataTextField="DirDetail" HeaderText="详细信息" Target="_new" /> 对于文件,我们使用showfile.aspx程序显示其属性和内容: <asp:HyperLinkColumn DataNavigateUrlField="FileName" DataNavigateUrlFormatString="showfile.aspx?file={0}" DataTextField="FileDetail" HeaderText="详细信息" Target="_new" />
在两个DataGrid(DirGrid,FileGrid)中我们分别设置了两个HyperLinkColumn列来导航到不同的处理页面。
在两个DataGrid中我们都使用了一个删除的按钮列:
<asp:ButtonColumn HeaderText="删除" Text="删除" CommandName="Delete" />
由于添加、更新、删除功能列都是DataGrid的默认模板列,所以可以在Vs.net中通过DataGrid的属性生成器自动添加此列。
获取上一页面所传递来的参数的代码:
因为在下面产生数据源的方法中需要使用由上一个页面传递过来的参数来确定目录和文件的名称,所以在页面的Page_Load方法里使用了下列代码:
strDir2List = Request.QueryString["dir"];
字符串strDir2List即传过来的目录名或文件名。
因为我们使用了两个DateGrid,就需要进行两次数据绑定,就有两个不同的生成数据源的方法。
生成目录数据网格(DirGrid)数据源的方法:
//通过此方法返回一个集合形式的数据视图DataView,用来初始化子目录的DataGrid ICollection CreateDataSourceDir() { dtDir = new DataTable(); DataRow dr; //向DataTable中添加新的数据列,共四列 dtDir.Columns.Add(new DataColumn("DirID", typeof(Int32))); dtDir.Columns.Add(new DataColumn("DirName", typeof(string))); dtDir.Columns.Add(new DataColumn("DelDir", typeof(string))); dtDir.Columns.Add(new DataColumn("DirDetail", typeof(string))); //根据传入的参数(目录名)得到此目录下所有子目录名的字符串数组 string [] DirEntries = Directory.GetDirectories(strDir2List); //使用foreach循环可以对未知长度的数组进行遍历循环 foreach(string DirName in DirEntries){ dr = dtDir.NewRow(); dr[0] = i;//序号 dr[1] = DirName;//文件夹名称 dr[3] = "删除"; dr[3] = "查看详情"; dtDir.Rows.Add(dr); i++; } DataView dvDir = new DataView(dtDir); //返回得到的数据视图 return dvDir; } 生成文件数据网格(FileGrid)数据源的方法: //通过此方法返回一个集合形式的数据视图DataView,用来初始化文件的DataGrid ICollection CreateDataSourceFile() { dtFile = new DataTable(); DataRow dr; dtFile.Columns.Add(new DataColumn("FileID", typeof(Int32))); dtFile.Columns.Add(new DataColumn("FileName", typeof(string))); dtFile.Columns.Add(new DataColumn("DelFile", typeof(string))); dtFile.Columns.Add(new DataColumn("FileDetail", typeof(string))); //根据传入的参数(目录名)得到此目录下所有文件名的字符串数组 string [] FileEntries = Directory.GetFiles(strDir2List); foreach(string FileName in FileEntries){ dr = dtFile.NewRow(); dr[0] = i; dr[1] = FileName; dr[2] = "删除"; dr[3] = "查看详情"; dtFile.Rows.Add(dr); i++; } dvFile = new DataView(dtFile); return dvFile; }
我们编程实现了两个DataSource只需在页面的Page_Load方法里对两个DataGrid进行数据绑定即可将得到的DataTable中的数据显示在aspx页面的DataGrid上。
数据绑定代码:
//对子目录数据列表DirGrid进行数据源定义和数据绑定 DirGrid.DataSource = CreateDataSourceDir(); DirGrid.DataBind(); //对文件数据列表FileGrid进行数据源定义和数据绑定 FileGrid.DataSource = CreateDataSourceFile(); FileGrid.DataBind();
通过我们上边介绍的主要方法,我们实现了对某个逻辑驱动器或目录中的所有子目录和文件进行了列表显示,并且可以根据显示结果更进一步的浏览子目录或者查看文件的属性和内容提要。浏览子目录仍然是通过listdir.aspx这个程序,没有任何子目录级别要求,没有目录深度限制。 删除子目录和文件的主要方法和代码:
在删除子目录时,我们需要用到Directory.Delete (string,bool)方法,此方法有两种:
1.public static void Delete(string);
从指定路径删除空目录。
2.public static void Delete(string, boolean);
删除指定的目录并(如果指示)删除该目录中的任何子目录,将boolean设置为true的话,则删除此目录下的所有子目录和文件,否则将boolean设置为false。
在这里我们使用了第二种方法,如果选择删除的话,将删除此目录下的所有子目录和文件。
注意:Directory 类的所有方法都是静态的,因而无需具有目录Directory的实例就可被调用。
/*实现删除子目录的方法,此方法为VS.NET自动添加,注意DataGridCommandEventArgs e为DirGrid中 CommandName="Delete" 的ButtonColumn的事件,通过此事件,我们可以得到是那一行的ButtonColumn按钮列被点击,进而确定我们需要删除的子目录的名称*/ private void DirGrid_DeleteCommand(object source, System.Web.UI.WebControls.DataGridCommandEventArgs e){ /*定义一个单元格,e.Item为此事件所发生行的所有项目,e.Item.Cells[1]为整个行的第二个单元格的内容,在此DataGrid中为子目录的名称 */ TableCell ItemCell = e.Item.Cells[1]; //得到此子目录的名称的字符串 string item = ItemCell.Text; //删除此子目录 Directory.Delete(item,true); //删除后进行数据绑定以更新数据列表 DirGrid.DataBind(); }
在删除文件时,我们需要用到File.Delete(string path);
注意:File 类的所有方法都是静态的,因而无需具有目录的实例就可被调用。
private void FileGrid_DeleteCommand(object source, System.Web.UI.WebControls.DataGridCommandEventArgs e) { TableCell ItemCell = e.Item.Cells[1]; //得到此文件名称的字符串 string item = ItemCell.Text; //删除此文件 File.Delete(item); //删除后进行数据绑定以更新数据列表 DirGrid.DataBind(); }
通过上边的主要方法我们在页面上实现了一个删除某一个子目录或者文件的功能,此功能在测试时需要慎重使用,一旦删除无法通过常规方法恢复。其他如目录或文件改名、修改内容等方法都可以在此程序基础上添加相应的功能,实现方法也很简单。各位爱好者可以通过添加相应功能,使之扩充为一个基于Web的服务器文件管理系统。我们也可以由此看到这个程序的危害性,一个没有对此安全隐患采取防范措施的服务器的文件系统就都暴露在了使用此程序的用户面前。 程序三:显示文件属性和内容的程序showfile.aspx
在显示属性和内容时需要用到的两个主要的类:
System.IO.FileInfo:提供创建、复制、删除、移动和打开文件的实例方法,并且帮助创建 FileStream 对象。
System.IO.StreamReader:实现一个 TextReader,使其以一种特定的编码从字节流中读取字符。除非另外指定,StreamReader的默认编码为 UTF-8,而不是当前系统的 ANSI 代码页。UTF-8 可以正确处理 Unicode 字符并在操作系统的本地化版本上提供一致的结果。
Showfile.aspx页面主要代码:
<asp:Label id="FileDetail" runat="server"/>
我们只是将文件的属性信息和部分内容显示在此Label上。所以没有其他复杂的代码。
获取文件信息和内容的主要代码都在Page_Load方法中(代码在showfile.aspx.cs文件中):
//接收传入的参数,确定需要操作的文件名称 strFile2Show = Request.QueryString["file"]; //根据文件名实例化一个FileInfo对象 FileInfo fi = new FileInfo(strFile2Show); FileDetail.Text = "文件名:"; FileDetail.Text += strFile2Show+"<br>"; FileDetail.Text += "文件大小"; //获得文件的大小,然后变换单位为KB FileDetail.Text += (fi.Length/1024).ToString()+"K<br>"; FileDetail.Text += "创建文件时间:"; //获得文件的创建日期 FileDetail.Text += fi.CreationTime.ToString(); FileDetail.Text += "上次访问时间:"; //获得文件的上次访问日期 FileDetail.Text += fi.LastAccessTime.ToString()+"<br>"; FileDetail.Text += "上次写入时间:"; //获得文件的上次写入日期 FileDetail.Text += fi.LastWriteTime.ToString()+"<br>"; //实例化一个StreamReader对象,用于读取此FileInfo的内容 StreamReader FileReader = fi.OpenText(); //定义一个长度为1000的字符数组作为缓冲区 char[] theBuffer = new char[1000]; /*ReadBlock方法:从当前流中读取最大数量的字符并从索引开始将该数据写入缓冲区。 参数: char[] buffer:方法返回时,包含指定的字符数组 int index:buffer 中开始写入的位置 int count:最多读取的字符数 */ int nRead = FileReader.ReadBlock(theBuffer,0,1000); FileDetail.Text += new String(theBuffer,0,nRead); //关闭此 StreamReader 并释放与之关联的所有系统资源 FileReader.Close();
到目前为止,我们实现了一个简单的web页面的服务器磁盘管理应用程序,可以查看、删除目录和文件。如果需要修改文件、新建文件和文件夹等功能,只需稍作修改,添加上相应的代码就可以。由于我们只是通过这个程序说明服务器中存在的安全隐患,所以在这里就不再实现这些功能了。
通过这三个简单的程序,我想大家已经能够清楚的认识到这一漏洞的危害性了,如果我们不加防范的话,其他用户的程序就能被恶意使用此功能的用户查看、删除,服务器的系统日志、系统文件也没有任何安全可言了。
|