后端代码
using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
namespace MvcApplication1.Controllers
{
public class HomeController : Controller
{
public ActionResult Index()
{
ViewBag.Message = "Welcome to ASP.NET MVC!";
return View();
}
public ActionResult About()
{
return View();
}
public JsonResult Test()
{
Person p = new Person();
p.Name = "zhangsan";
p.Age = 20;
p.Created = DateTime.Now;
return Json(p, JsonRequestBehavior.AllowGet);
}
}
public class Person
{
public string Name { get; set; }
public int Age { get; set; }
public DateTime Created { get; set; }
}
}
前端代码
@{
ViewBag.Title = "Home Page";
}
<h2>@ViewBag.Message</h2>
<p>
To learn more about ASP.NET MVC visit <a href="http://asp.net/mvc" title="ASP.NET MVC Website">http://asp.net/mvc</a>.
</p>
<input type="button" value="okkkkkk" onclick="s();"/>
<script type="text/javascript">
function s() {
$.get("/home/test",{r:Math.random()}, function (res) {
alert(res.Name);
alert(res.Created);
alert(getDate(ConvertJSONDateToJSDateObject(res.Created)));
alert(getDateTime(ConvertJSONDateToJSDateObject(res.Created)));
})
}
function ConvertJSONDateToJSDateObject(jsondate) {
var date = new Date(parseInt(jsondate.replace("/Date(", "").replace(")/", ""), 10));
return date;
}
function getDate(date) {
var year = date.getFullYear();
var month = date.getMonth() + 1;
var day = date.getDate();
return year + "-" + month + "-" + day;
}
/* 获取日期时间格式*/
function getDateTime(date) {
var year = date.getFullYear();
var month = date.getMonth() + 1;
var day = date.getDate();
var hh = date.getHours();
var mm = date.getMinutes();
var ss = date.getSeconds();
return year + "-" + month + "-" + day + " " + hh + ":" + mm + ":" + ss;
}
</script>
盼望着,盼望着,批量数据替换助手V2.0版终于发布了,^\(^o^)/。
你可以点击 批量数据替换助手V1.0版 了解它的由来。
很感谢园子里的朋友cdboy、yongfa365、心儿醉 xinerzhui、Vincent.Q提出了他们对1.0版本的修改意见和鼓励。在本次2.0版本中主要对软件操作的友好性以及大数据量处理性能优化做了改进。主要修改如下:
1.改进点击替换按钮时没有选中任何表的提示信息。
2.遍历表数据时不采用原先的DataTable来做数据载体,而改用SqlDataReader循环读取数据,读取数据的同时对数据进行处理。这样一来,节省了内存空间,数据读取速度也提高了。
#region 得到要更新的sql语句集合
/// <summary>
/// 得到要更新的sql语句集合
/// </summary>
/// <param name="sqlList"></param>
/// <param name="tabInfo"></param>
/// <param name="searchString"></param>
/// <param name="replaceString"></param>
/// <param name="kt"></param>
public static void GetUpdateSqlList(ref List<string> sqlList, TableInfo tabInfo, string searchString, string replaceString, KeyType kt)
{
SqlDataReader dr = GetTableData(tabInfo);
List<ColumnInfo> primaryKeys = tabInfo.GetCols(ColType.PrimaryKey); //筛选类型为主键的列
List<ColumnInfo> cols = tabInfo.GetCols(ColType.Normal); //筛选非主键列
ColumnInfo columnInfo = null;
List<ColumnInfo> colInfoList = new List<ColumnInfo>();
while (dr.Read())
{
colInfoList.Clear();
for (int i = 0; i < primaryKeys.Count; i++)
{
columnInfo = primaryKeys[i];
primaryKeys[i].ColValue = dr[columnInfo.ColName].ToString();
}
for (int i = 0; i < cols.Count; i++)
{
columnInfo = new ColumnInfo();
columnInfo.ColName = cols[i].ColName;
columnInfo.ColValue = dr[columnInfo.ColName].ToString();
colInfoList.Add(columnInfo);
}
if (HasCheckedReplace(ref colInfoList, searchString, replaceString, kt))
{
sqlList.Add(GetRowUpdateSql(tabInfo, colInfoList, primaryKeys));
}
}
dr.Close();
}
#endregion
3.采用批量sql脚本更新策略,即当有1w条sql语句需要执行时我们将它分成10次发给数据库,每次发送1k条sql语句的脚本块。这样一来节省了与数据库的交互次数,同时分多次发送的策略可以有效的降低网络带宽的占用。
List<string> sqlList = new List<string>();
foreach (TableInfo tabInfo in tabList)
{
ReplaceHelper.GetUpdateSqlList(ref sqlList, tabInfo, searchString, replaceString, kt);
}
StreamWriter sw = File.AppendText(string.Format("update{0}.sql",DateTime.Now.ToString("yyyyMMddHHmmss"))); //将更新Sql语句写入文件
int executeSqlCount = 1000; //单次批处理包含sql语句的条数
int executeTimes = (sqlList.Count % executeSqlCount) == 0 ? (sqlList.Count / executeSqlCount) : (sqlList.Count / executeSqlCount) +1; //批处理的次数
StringBuilder sb = null;
int startIndex = 0;
int endIndex = 0;
pBar1.Visible = true;
pBar1.Minimum = 1;
pBar1.Value = 1;
pBar1.Step = executeSqlCount;
pBar1.Maximum = sqlList.Count;
for (int i = 0; i < executeTimes; i++)
{
sb = new StringBuilder();
startIndex = i * executeSqlCount;
endIndex = startIndex + executeSqlCount -1;
endIndex = endIndex >= sqlList.Count ? sqlList.Count -1 : endIndex;
for (int j = startIndex; j <= endIndex; j++)
{
sb.AppendLine(sqlList[j]);
}
sw.Write(sb.ToString());
ReplaceHelper.ExecuteSql(sb.ToString());
pBar1.PerformStep();
}
sw.Close();
4.替换数据的同时将sql语句保存到文本文件中,已备以后使用,更方便和人性化。
就这么多,欢迎各位童鞋有发表你的意见。最后附上程序源码的下载地址,http://dl.dbank.com/c0wexphaza
前段时间网站被挂马,数据库表中很多文本字段都被加上了一段js脚本。修复完程序漏洞之后便开始着手清理这些被注入的数据,其间参考了一些网上的方法,大都是写一个存储过程进行一个表一个表逐一清理。这种方法操作繁琐,而且一般不是很懂数据库的人很难操作。于是萌发了要写一个小程序的念头,经过两天时间的折腾这个小软件终于和各位见面了,希望各位童鞋多给点意见。说了这么些之后还是先上界面吧,^..^

现在就来说说这个小程序的开发思路吧。
第一步:通过 sp_helpdb系统存储过程得到SqlServer中的所有数据库名称。
View Code
#region 测试数据库连接,并显示数据库列表
/// <summary>
/// 测试数据库连接,并显示数据库列表
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void btnTest_Click(object sender, EventArgs e)
{
this.btnTest.Enabled = false;
saveConfig();
ConfigInfo.Server = this.txtIP.Text.Trim();
ConfigInfo.DataBase = "master";
ConfigInfo.UID = this.txtUID.Text.Trim();
ConfigInfo.Pwd = this.txtPwd.Text.Trim();
try
{
DataTable dt = Data.SqlHelper.ExecuteDataset(ConfigInfo.getConnect(), CommandType.Text, "sp_helpdb").Tables[0];
this.cmbDataBaseList.DataSource = dt;
this.cmbDataBaseList.DisplayMember = "name";
this.cmbDataBaseList.SelectedIndex = 0;
this.cmbDataBaseList.DropDownStyle = ComboBoxStyle.DropDownList;
this.ExecuteFilterBtn.Enabled = true;
}
catch (Exception ex)
{
this.ExecuteFilterBtn.Enabled = false;
MessageBox.Show(string.Format("错误:{0}!",ex.Message),"错误提示", MessageBoxButtons.OK, MessageBoxIcon.Error);
}
finally
{
this.btnTest.Enabled = true;
}
}
#endregion
第二步:当选择某个数据库时得到数据库里面的所有表信息,通过下面Sql语句就可以查询到了。
select [name] from sysobjects where xtype='u' order by [name] asc
View Code
#region 当选择不同的数据库时,读取数据库的表信息
/// <summary>
/// 当选择不同的数据库时,读取数据库的表信息
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
this.chkboxTableList.Items.Clear();
ConfigInfo.DataBase = ((DataRowView)this.cmbDataBaseList.SelectedItem)["name"].ToString();
DataSet ds = Data.SqlHelper.ExecuteDataset(ConfigInfo.getConnect(), CommandType.Text, "select [name] from sysobjects where xtype='u' order by [name] asc");
foreach (DataRow row in ds.Tables[0].Rows)
{
this.chkboxTableList.Items.Add(row["name"].ToString());
}
}
#endregion
第三步:当点击替换按钮时获取被选中表的信息,并遍历表中的行列信息,并进行查找替换。
View Code
#region 执行批量替换操作
/// <summary>
/// 执行批量替换操作
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void ExecuteFilterBtn_Click(object sender, EventArgs e)
{
saveConfig();
total = 0;
if (this.chkboxTableList.CheckedIndices.Count == 0) return; //没有选中任何表的情况
if (this.txtSearchKey.Text.Trim() == "")
{
DialogResult result = MessageBox.Show("当前查找内容为空,确认此操作?", "提示", MessageBoxButtons.YesNo, MessageBoxIcon.Question, MessageBoxDefaultButton.Button1);
if (result == DialogResult.No) return;
}
this.ExecuteFilterBtn.Enabled = false;
List<TableInfo> tabList = new List<TableInfo>();
string searchString = this.txtSearchKey.Text.Trim() == "" ? " " : this.txtSearchKey.Text;
string replaceString = this.txtReplaceStr.Text;
KeyType kt = this.chkIsRegex.Checked == true ? KeyType.Regex : KeyType.Text;
bool isRegex = this.chkIsRegex.Checked;
//得到被选中表的基本信息,并添加到集合中
foreach (int index in this.chkboxTableList.CheckedIndices)
{
string tabName = this.chkboxTableList.Items[index].ToString();
TableInfo tInfo = FilterInfo.initTableInfo(tabName);
if (tInfo == null)
{
continue;
}
tabList.Add(tInfo);
}
try
{
if (tabList.Count == 0) return; //没有符合检测的数据表
pBar1.Visible = true;
pBar1.Minimum = 1;
pBar1.Maximum = tabList.Count;
pBar1.Value = 1;
pBar1.Step = 1;
//循环过滤表中要替换的数据
foreach (TableInfo info in tabList)
{
FilterInfo.Execute(info, searchString, replaceString, kt);
pBar1.PerformStep(); //进度条
}
}
catch (Exception ex)
{
MessageBox.Show(string.Format("异常:{0}", ex.Message), "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
return;
}
finally
{
this.ExecuteFilterBtn.Enabled = true;
}
MessageBox.Show(string.Format("数据替换完毕,共有{0}行数据被修改!",total),"消息", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
#endregion
以上就是整个大致思路,详情可以参看源代码。
附带一些操作截图,希望大家可以看的更清楚一些。

这个就是被注入的数据,当然实际的会有区别。

编写查找内容,并启用正则匹配功能。

哈哈,数据终于恢复原貌!!
源程序下载地址:http://dl.dbank.com/c0qh0l03dc
由于项目的关系,前段时间研究了一下正则表达式高级特性,如捕获组、平衡组、零宽断言等,
着实让我体会了一把它的正则强大之处。之前也用过正则表达式,其应用无外乎输入验证和简
单的文字替换等功能。
废话不多说,以下是我使用正则的一些场景:
场景1:输入规则验证,比如邮件格式、密码格式等。
场景2:文本内容批量替换。这里我一般使用dreamweaver来匹配替换,主要原因是它的替换匹配模式
对正则的高级特性支持比较不错,如捕获组、零宽断言都基本上支持。

上图的正则主要是把ecshop文件夹里所有文件中的link和img标记的href和src属性都加上一个反斜杠,如将<img src="123.jpg">替换成<img src="/123.jpg">,这样一来一点替换全部按钮整个世界都清净了,^^
场景3:当前选中页面链接变色代码设计。还是先来看图片吧,不知道这样的需求大家是怎么做的,反正我用了正则。

场景4:很不幸网站被注入了,一时有没找到注入点,只好正则匹配木马脚本,将其全部删除。
个人觉得正则用处真挺大的,如果你也有什么更好的建议别忘了@我!!
之前有朋友问到了这个问题,空闲时间写了这段代码,还望大虾们指正。
页面基类代码
using System;
using System.Collections.Generic;
using System.Web;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace test
{
public class pageBase : Page
{
private readonly static string _host = "http://localhost:18447";
private bool _isallowacross = false;
/// <summary>
/// 数据提交方式,如get、post或head
/// </summary>
public string HttpMethod
{
get {
return Request.HttpMethod.ToLower();
}
}
/// <summary>
/// 获取客户上次请求的uri地址
/// </summary>
public string UrlReferrer
{
get {
return Request.UrlReferrer == null ? "" : Request.UrlReferrer.ToString();
}
}
/// <summary>
/// 是否允许站外提交数据
/// </summary>
public bool IsAllowAcross
{
set { _isallowacross = value; }
get { return _isallowacross; }
}
/// <summary>
/// 检测跨站数据提交
/// </summary>
public void CheckAcross()
{
if (!IsAllowAcross)
{
if (HttpMethod == "post" && UrlReferrer.IndexOf(_host) == -1)
{
Response.Write("禁止跨站提交数据,请求已终止!");
Response.End();
}
}
}
/// <summary>
/// 捕获异常信息
/// </summary>
/// <param name="e"></param>
protected override void OnError(EventArgs e)
{
base.OnError(e);
Response.Write(string .Format("发生一个未处理的错误,请<a href=\"{0}\">重试</a>!信息:{1}",UrlReferrer,Server.GetLastError().Message));
Response.End();
}
protected override void OnInit(EventArgs e)
{
base.OnInit(e);
CheckAcross();
}
}
}
调用页面代码
public partial class index : pageBase
{
protected void Page_Load(object sender, EventArgs e)
{
if (HttpMethod == "post")
{
this.lit.Text = string.Format("欢迎用户:{0}。", Request.Form["txt"]);
Response.Write(string.Format("客户上次请求Url:{0}<br/>", Request.UrlReferrer));
}
}
////默认禁止跨站数据提交,可通过重写基类OnInit事件进行开启
//protected override void OnInit(EventArgs e)
//{
// IsAllowAcross = true;
// base.OnInit(e);
//}
}