[转载]ASP.NET网页代码模型分析

mikel阅读(831)

[转载]ASP.NET网页代码模型分析 – 无风听海 – 博客园.

1. ASP.NET网页有两部分组成

可视元素,包括标记、服务器控件和静态文本

页的编程逻辑,包括事件处理程序和其他代码。

2. ASP.NET 提供两个用于管理可视元素和代码的模型,即单文件页模型和代码隐藏页模型。

两个模型功能相同,两种模型中可以使用相同的控件和代码

3. 单文件页模型

在单文件页模型中,页的标记及其编程代码位于同一个物理 .aspx 文件中。 编程代码位于 script 块中,该块包含 runat=”server” 特性,此特性将其标记为 ASP.NET 应执行的代码。

代码文件如下 SinglePage.aspx

<%@ Page Language=C# %>

<script runat=“server”>

void Button1_Click(Object sender, EventArgs e)

{

Label1.Text = “Clicked at “ + DateTime.Now.ToString();

}

</script>

<html>

<head>

<title>Single-File Page Model</title>

</head>

<body>

<form runat=“server”>

<div>

<asp:Label id=“Label1”

runat=“server” Text=“Label”>

</asp:Label>

<br />

<asp:Button id=“Button1”

runat=“server”

onclick=“Button1_Click”

Text=“Button”>

</asp:Button>

</div>

</form>

</body>

</html>

4. 代码隐藏页模型

通过代码隐藏页模型,可以在一个文件(.aspx 文件)中保留标记,并在另一个文件中保留编程代码,但并不是所有的语言都支持该模型,只有支持分部类才可以。

代码文件 Sample.aspx

<%@ Page Language=C# CodeFile=“Sample.aspx.cs”

Inherits=“_Default” AutoEventWireup=“true” %>

<html>

<head runat=“server” >

<title>Code-Behind Page Model</title>

</head>

<body>

<form id=“form1” runat=“server”>

<div>

<asp:Label id=“Label1”

runat=“server” Text=“Label” >

</asp:Label>

<br />

<asp:Button id=“Button1”

runat=“server”

onclick=“Button1_Click”

Text=“Button” >

</asp:Button>

</div>

</form>

</body>

</html>

代码文件Sample.cs

sing System;

using System.Web;

using System.Web.UI;

using System.Web.UI.WebControls;

public partial class _Default:System.Web.UI.Page

{

protected void Button1_Click(object sender, EventArgs e)

{

Label1.Text = “Clicked at “ + DateTime.Now.ToString();

}

}

5. 两种模型编译后各个文件产生的类

sample.aspx生成的类

Sample.cs产生的类

Single.aspx产生的文件

生成的工厂类

由以上可以看到两种模型最终产生的类是相同的,代码隐藏页模型巧妙的运用了面向对象的继承特性实现了代码分离!

[转载]iPhone中调用WCF RESTFUL Service

mikel阅读(1073)

[转载]iPhone中调用WCF RESTFUL Service – 用自己的语言写个Hello World – 博客园.

在前面的一篇文章:跨平台iPhone中调用WCF服务中 讲述的如何在iPhone中调用WCF服务。我现在开发是调用webservice的,方式和那篇文章一样。需要定义soap,然后异步去调用服务端的方 法,等服务端执行完成,然后在iPhone客户端接受返回的XML,最后解析返回的XML。这种方式用起来非常的不方便,每一次调用即需要写自定义的 soap,又要解析XML。这篇文章我将讲述一下如何调用restful方式的WCF服务。

REST(Representational State Transfer)是一种轻量级的Web Service架构风格,其实现和操作明显比SOAP和XML-RPC更为简洁,可以完全通过HTTP协议实现,还可以利用缓存Cache来提高响应速 度,性能、效率和易用性上都优于SOAP协议。使用WCF创建restful分格的服务是非常方便的。这篇文章,我通过一个demo来展示如何在 iPhone中调用wcf restful service。

创建一个wcf restful service。

1、创建一个数据交换实体类

///
/// User实体类
///
[DataContract]
public class User
{
///
/// 用户名
///
[DataMember(Order = 0)]
public string Name { get; set; }

///
/// 生日
///
[DataMember(Order = 1)]
public string DayOfbirth { get; set; }
}

2、服务契约:定义了三个方法,分别用来获取用户的XML格式、json格式以及创建用户。

[ServiceContract]
public interface IService1
{
///
/// 创建用户
///
///
/// 获取用户信息,json格式
///
///
<span> </span>用户名 [OperationContract]
[WebGet(
UriTemplate = "User/{name}",
ResponseFormat = WebMessageFormat.Json)]
User GetUser(string name);

///
/// 获取用户信息,XML格式
///
///
<span> </span>用户名 ///
///
[OperationContract]
[WebGet(
UriTemplate = "UserXML/{name}",
ResponseFormat = WebMessageFormat.Xml)]
User GetUserXML(string name);

///
/// 创建用户信息
///
///
<span> </span>用户名 ///
生日 ///
[OperationContract]
[WebInvoke(UriTemplate = "User/{name}/{dayOfbirth}",
Method = "POST",
ResponseFormat = WebMessageFormat.Json)]
User CreateUser(string name, string dayOfbirth);

}

3、服务实现:这里简单处理。

public class Service1 : IService1
{
public User GetUser(string name)
{
return new User { Name = name, DayOfbirth = new DateTime(1986, 10, 23).ToString() };
}

public User GetUserXML(string name)
{
return new User { Name = name, DayOfbirth = new DateTime(1986, 10, 23).ToString() };
}
public User CreateUser(string name, string dayOfbirth)
{
return new User { Name = name, DayOfbirth = dayOfbirth };
}
}

4、对于vs2008创建的wcf服务,需要在.svc文件中加入下面代码:

Factory="System.ServiceModel.Activation.WebServiceHostFactory"

6、在iis发布服务。

iPhone客户端调用:

这里使用ASIHTTPRequest,它是一个直接在CFNetwork上做的开源项目,提供了一个比官方更方便更强大的HTTP网络传输的封装,非常的好用。

在xcode中拖一个简单的界面,如下图,分别调用服务端的三个方法:

定义下面三个方法与三个button的点击事件对应:

- (IBAction)fetchXML:(id)sender;
- (IBAction)fetchJson:(id)sender;
- (IBAction)createJson:(id)sender;

三个点击事件的具体实现:下面的代码为了简单起见,直接将xml和json输入。比较好的做法是:在iPhone也定义一个User类,将json或者XML转换为User实体对象。

- (IBAction)fetchXML:(id)sender
{
NSURL *url = [NSURL URLWithString:@"http://10.5.23.117:21924/Service1.svc/UserXML/zhuqilin"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
NSString *response = [request responseString];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"xml格式"
message:response
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alertView show];
[alertView release];
}

}
- (IBAction)fetchJson:(id)sender
{
NSURL *url = [NSURL URLWithString:@"http://10.5.23.117:21924/Service1.svc/User/zhuqilin"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
NSString *response = [request responseString];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"JSON格式"
message:response
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alertView show];
[alertView release];
}
}
- (IBAction)createJson:(id)sender
{
NSURL *url = [NSURL URLWithString:@"http://10.5.23.117:21924/Service1.svc/User/zhuqilin/1986-09-20"];
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
[request setRequestMethod:@"POST"];
[request startSynchronous];
NSError *error = [request error];
if (!error) {
NSString *response = [request responseString];
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"创建用户"
message:response
delegate:nil
cancelButtonTitle:@"OK"
otherButtonTitles:nil];
[alertView show];
[alertView release];
}
}

输出结果:

1、获取json格式的数据

2、获取xml格式的数据

3、创建一个用户实体:

总结:本文通过一个简单的例子说明了如何在iPhone中调用wcf restful服务。你会感觉到这个方式,比去定义soap去调用要好很多,如果你有更方便的方式,请一定要告诉我哈。

本文代码:http://files.cnblogs.com/zhuqil/sourcecode.rar

作者:朱祁林
出处:http://zhuqil.cnblogs.com
本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,否则保留追究法律责任的权利。

[转载]使用 Glimpse 调试 ASP.NET MVC 应用

mikel阅读(1059)

[转载]使用 Glimpse 调试 ASP.NET MVC 应用 – 冠军 – 博客园.

Glimpse 类似于客户端调试器 FireBug,它使用 JavaScript 实现,但是还连接到 ASP.NET 服务器端。
Glimpse 不仅包括更好的路由调试器,还对使用不多,但是非常有用的 Trace.Write() 提供了更好的支持。
像在实战系列一样,你现在就可以跟着我开始,不超过 5 分钟就可以完成。
使用 NuGet ,为一个新的 ASP.NET MVC 程序,或者 WinForm 程序安装 Glimpse 支持。
在运行程序之前,在程序中加入一些 Trace.Write 和 Trace.TraceError。
1 public ActionResult Index() 2 { 3 ViewBag.Message = "Welcome to ASP.NET MVC!"; 4 Trace.Write("Hey, this is nice"); 5 Trace.TraceWarning("Oh, this could be bad."); 6 return View(); 7 } 8 9 public ActionResult About() 10 { 11 Trace.TraceError("Oh, no! That's bad"); 12 return View(); 13 }
现在,运行程序,可以通过书签打开 Glimpse,但是,我喜欢通过访问 http://localhost:portname/Glimpse/Config,然后点击大个的 Turn Glimpse On 按钮来启用,有一天,我也会将它加入到书签中。
接着,在访问站点的时候,注意到 Glimpse 的控制面板出现在页面的底部,它不是浏览器的插件,全部是使用 JavaScript 实现的。
在 Trace 选项卡中可以看到 Trace 的输出,不比 Trace.axd 更棒吗?如果切换到 Router 选项卡,我还可以看到当前请求使用的路由。
Glimpse, 我会将它加入到我的收藏中每天使用它,我建议你也这样做。
我仅仅了解一些表面的使用,你可以到 Glimpse 的站点深入探索:http://www.getglimpse.com.

[转载]Mongodb从配置到应用

mikel阅读(1061)

[转载]Mongodb从配置到应用 – 每一点知识的积累都是对生命的充实!!! – 博客园.

早就想写一篇Mongodb的文章了,苦于木有时间呀,今天抽空将我所学习到的Mongodb知识整合一下,分享出来,部分Mongodb知识来源于网络.此处不给出链接,如果有侵犯,请及时联系我…

一,Mongodb简介

Mongo(http://www.mongodb.org/)是一个高性能,开源(代震军大牛正在研究Mongodb的源码,大家可以去看看http://www.cnblogs.com/daizhj/),模式自由(schema-free)的文档型数据库,它在许多场景下可用于替代传统的关系型数据库或键/值(key-value)存储方式。Mongo使用C++开发,

具有以下特性:

  1. 面向集合的存储:适合存储对象及JSON形式的数据。
  2. 动态查询:Mongo支持丰富的查询表达式。查询指令使用JSON形式的标记,可轻易查询文档中内嵌的对象及数组。
  3. 完整的索引支持:包括文档内嵌对象及数组。Mongo的查询优化器会分析查询表达式,并生成一个高效的查询计划。
  4. 查询监视:Mongo包含一个监视工具用于分析数据库操作的性能。
  5. 复制及自动故障转移:Mongo数据库支持服务器之间的数据复制,支持主-从模式及服务器之间的相互复制。复制的主要目标是提供冗余及自动故障转移。
  6. 高效的传统存储方式:支持二进制数据及大型对象(如照片或图片)。
  7. 自动分片以支持云级别的伸缩性(处于早期alpha阶段):自动分片功能支持水平的数据库集群,可动态添加额外的机器。
  8. 模式自由(schema-free),意味着对于存储在mongodb数据库中的文件,我们不需要知道它的任何结构定义。如果需要的话,你完全可以把不同结构的文件存储在同一个数据库里。
  9. 支持Python,PHP,Ruby,Java,C,C#JavaScript,Perl及C++语言的驱动程序,社区中也提供了对Erlang及.NET等平台的驱动程序。

使用场合:

  1. 网站数据:Mongo非常适合实时的插入,更新与查询,并具备网站实时数据存储所需的复制及高度伸缩性。
  2. 缓存:由于性能很高,Mongo也适合作为信息基础设施的缓存层。在系统重启之后,由Mongo搭建的持久化缓存层可以避免下层的数据源 过载。
  3. 大尺寸,低价值的数据:使用传统的关系型数据库存储一些数据时可能会比较昂贵,在此之前,很多时候程序员往往会选择传统的文件进行存储。
  4. 高伸缩性的场景:Mongo非常适合由数十或数百台服务器组成的数据库。Mongo的路线图中已经包含对MapReduce引擎的内置支持。
  5. 用于对象及JSON数据的存储:Mongo的BSON数据格式非常适合文档化格式的存储及查询。

所谓“面向集合”(Collenction- Orented),意思是数据被分组存储在数据集中,被称为一个集合(Collenction)。每个集合在数据库中都有一个唯一的标识名,并且可以包含 无限数目的文档。集合的概念类似关系型数据库(RDBMS)里的表(table),不同的是它不需要定义任何模式(schema)。

二,Ubuntu 下配置Mongodb

Ubuntu知识扫盲:

chown -R : 对目前目录下的所有档案与子目录进行相同的权限变更(即以递回的方式逐个变更)

nohup命令:如果你正在运行一个进程,而且你觉得在退出帐户时该进程还不会结束,那么可以使用nohup命令。该命令可以在你退出帐户/关闭终端之后继续运行相应的进程。nohup就是不挂起的意思( n ohang up)。

Mongodb目前最新版本是1.8.1
首先启动终端 :
输入 wget http://fastdl.mongodb.org/linux/mongodb-linux-i686-1.8.1.tgz
下载mongodb-linux-i686-1.8.1.tgz安装包
解压 tar -zxvf mongodb-linux-i686-1.8.1.tgz

默认情况下Mongodb会在/data/db/ 这个文件夹存放数据

在当前目录下输入如下命令,创建用户 :
//添加一个mongodb用户
adduser mongodbxiao
//设置密码
passwd mongodb
3

继续输入

sudo mkdir -p /data/db/
//把”/data/db/”的属主改成mongodb用户
$ sudo chown mongodbxiao /data/db/
$ chown -R mongodb:mongodbxiao /data
当然 可以 通过–dbpath 命令 指定MongoDB将数据存储到另外的目录中去。

在运行下面的语句之前需要安装一下mongo shell 否则会收到提示:程序“mongo”尚未安装。
apt-get install mongodb-clients

运行数据库
$  ./mongodb-linux-i686-1.8.1/bin/mongod
$ ./mongodb-linux-i686-1.8.1/bin/mongo
> db.test.save({123123:’哈哈哈’})
> db.test.find();

创建数据库并添加一条记录,最后查询结果:
2

到此证明我们在Ubuntu下配置Mongodb成功..

ps:使用Ubuntu过程中经常会遇到这个错误:

1

只需要输入强制解锁,命令即可解决。

sudo rm /var/cache/apt/archives/lock

sudo rm /var/lib/dpkg/lock

三,Mongodb客户端管理工具

Try MongoDB

不用安装就可以试用MongoDB,和tryredis一样,是一个基于web的shell模拟工具,可以让你在不用安装MongoDB的情况下试用MongoDB的各种功能.

Mongo3 – MongoDB 集群管理工具

MongoVUE

一个windows下的客户端管理工具,我推荐这个,非常不错.有点类似于mySQL管理工具..

5

四,Mongodb C#版驱动

第一款:mongodb-csharp 项目地址:http://github.com/samus/mongodb-csharp

简单介绍:该驱动是比较全的驱动,更新随度非常快,有人已经应用到项目中去,并且表现非常好。目前他们的团队正在致力于连接管理这部分功能的扩展例如:自动重连,连接池等等。

第二款:mongodb-net 项目地址:http://code.google.com/p/mongodb-net/

简单介绍:该开发还在进行中,有些功能还没有实现。

第三款:MongoDB.Emitter 项目地址:http://bitbucket.org/gwbasic/mongodb.emitter/

简单介绍:提供了强类型支持

第四款:CSMongo 项目地址:http://somewebguy.wordpress.com/2010/02/21/building-a-mongo-driver-part-1/

简单介绍:实现了部分功能,并且没有可下载的代码。但是你可以看他的博客以了解这种驱动的思想。

第五款:simple- mongodb 项目地址:http://code.google.com/p/simple-mongodb/

简单介绍:没有提供源代码,以JSon为核心。

最后一个是对第一款某些地方的增强,地址http://deserialized.com/convert-csharp-classes-to- and-from-mongodb-documents-automatically-using-net-reflection

第六款:NoRM 项目地址:http://github.com/atheken/NoRM

介绍:增强了第一种,支持强类型。

五,Mongodb 与SQL 语句对照

此处用mySQL中的sql语句做例子,C# 驱动用的是samus,也就是上文中介绍的第一种.

引入项目MongoDB.dll

//创建Mongo连接

var mongo = new Mongo("mongodb://localhost");

mongo.Connect();

//获取一个数据库,如果没有会自动创建一个

var db = mongo.GetDatabase("movieReviews");

//创建一个列表,并为这个列表创建文档

var movies = db.GetCollection("movies");

连接没问题之后,现在让我们用mysql 与mongodb的一些语句做下对比:

MongoDB Mysql
查询全部 movies.find(new Document()) SELECT * FROM movies
条件查询 movies.Find(new Document { { “title”, “Hello Esr” } }); SELECT * FROM movies WHERE title= ‘foobar’
查询数量 movies.Find(new Document { { “title”, “测试2” } }).Documents.Count(); SELECT COUNT(*) FROM movies WHERE `title` = ‘foobar’
数量范围查询 1, movies.Find(new Document().Add(“$where”, new Code(“this.num > 50”)));

2, movies.Find(new Document().Add(“num”,  new Document().Add(“$gt”,50)));
($gt : > ; $gte : >= ; $lt : < ; $lte : <= ; $ne : !=)

3,movies.Find(“this.num > 50”);

4,movies.Find(new Document().Add(“$where”,new Code(“function(x){ return this.num > 50};”)));

select * from movies where num > 50
分页查询 movies.Find(new Document()).Skip(10).Limit(20); SELECT * FROM movies  limit 10,20
查询排序语句 movies.Find(new Document()).Sort(new Document() { { “num”, -1 } }); SELECT * FROM movies ORDER BY num DESC
查询指定字段 movies.Find(new Document().Add(“num”, new Document().Add(“$gt”, 50)), 10, 0, new Document() { { “title”, 1 } }); select title from movies where num > 50
插入语句 movies.Insert(new Document() { { “title”, “测试” }, { “resuleData”, DateTime.Now } }); INSERT INOT movies (`title`, `reauleDate`) values (‘foobar’,25)
删除语句 movies.Remove(new Document() { { “title”, “Hello Esr” } }); DELETE * FROM movies
更新语句 movies.Update(new Document() { { “title”, “测试2” } }
, new Document() { { “title”, “测试11111” } });
UPDATE movies SET `title` = ‘测试1111’ WHERE `title` = ‘测试1111’
Linq查询 (from item in db.GetCollection(“movies”).Linq()
where ((string)item[“title”]).StartsWith(“Esr”)
select item);
select * from movies where title like ‘%Esr’

这里只举出了几个比较典型的例子,可以这么说,只要mysql可以完成的sql语句,在mongodb里面都可以实现.

[原创]DedeCMS模板使用笔记:使用if判断

mikel阅读(969)

常常我们需要对模板中字段的值进行非空判断,根据是否为空的结果进行相应的显示,于是从网上搜了下相关的方法,结合网站模板进行了操作总结出如下方法可以实现判断功能,代码如下:

{dede:field.zufang_tel php=yes}
if(@me==""||empty(@me))
@me="<p>无</p>";
{/dede:field.zufang_tel}

注释:
@me:就是当前字段的值,你可以在if中给其赋值,然后判断结束后它的值就变成你赋的值,打印出来

[转载]dede英文建站SEO中url优化

mikel阅读(913)

[转载]dede url优化_点滴∮生活_百度空间.

很多国内的网友做英文站都选择了织梦,其实织梦确实很强大,不过个人还是建议使用国外比较成熟的CMS或者wp都可以的,不过部分用户已经习惯了织梦,而且采集比较顺手,所以就分享了这篇关于用
织梦也就是dedecms做英文站需要改动的地方。

首先就是编码了:

就是安装utf-8的dede……然后在dede论坛里找个英文模板,

安装好后,看看前台,已经成了英文版的了

开始做模板,可以仿照英文站来做。

模板制作要注意几点:

1.字符集问题:charset=utf-8

2.字体用Verdana, Arial, Helvetica, sans-serif,这样的字体显示英文更好看

3,所有页面上不要出现中文字符,比如全角的空格

4.页面布局,细节等要符合老外的习惯

如:时间格式为“月-日-年”,对应的dede标签为:[field:pubdate function=strftime(‘%m-%d-%Y’,@me)/]
5.
SEO细节

(1)文章的url处理

大家应该都清楚,google对于url地址的重视程度很高,同一篇标题为old food new tricks的文章,如果url显示为 http://www.xxx.com/list1/20070928/5104.html 显然没有http://www.xxx.com/list1/old-food-new-tricks.html 的权重高。dede默认的生成的页面地址为前者,怎么改成后者显示类型呢?

进入后台,修改栏目的文章命名规则,默认的为:{typedir}/{Y}{M}{D}/{aid}.html

修改为:{typedir}/{pinyin}.html     我去掉了{Y}{M}{D},这样减少文章的层级,有利于引擎收录。

具体的修改方法,参考如下:

如题,使用dede让文章标题页显示路径为标题拼音.html,例如:文章标题为:站友网是什么啊,文章路径显示:zhanyouwangshishenmea.html,这样显示的好处是什么?靠,这个还用我说?

方法:
选择:网站栏目管理,修改栏目的高级选项,文章命名规则:{typedir}/{Y}{M}{D}/{aid}.html 这是默认的状态
修改为:{typedir}/{pinyin}.html 我觉得{Y}{M}{D}没什么用,所以也去掉了。
重新更新一下,看看是否有效果?

别着急,现在显示出拼音了,zhanyouwangshishenmea_1.html,但是后面还多了个_1,怎么去掉这个呢?
修改include里面的inc_channel_unit_function文件,找到$articleRule = str_replace(“{pinyin}”,GetPinyin($title).”_”.$aid,$articleRule); 把.”_”.$aid去掉,就可以了!
如果文章标题是英文的,会在单词之间加_,但是单词中间加_对gg来说没什么意义,必须改成“-”才可以,修改方法如下

打开 include/inc/inc_fun_funAdmin.php

for($i=0;$i<$slen;$i++){
if(ord($str[$i])>0x80)
{
$c = $str[$i].$str[$i+1];
$i++;
if(isset($pinyins[$c])){
if($ishead==0) $restr .= $pinyins[$c];
else $restr .= $pinyins[$c][0];
}else $restr .= “-“;
}else if( eregi(“[a-z0-9]”,$str[$i]) ){   $restr .= $str[$i]; }
else{ $restr .= “-“; }
}


$restr .= “-“; 这些东西

拼音中间加“-”

修改include\inc\inc_fun_funAdmin.php

for($i=0;$i<$slen;$i++){
if(ord($str[$i])>0x80)
{
$c = $str[$i].$str[$i+1];
$i++;
if(isset($pinyins[$c])){
if($ishead==0) $restr .= $pinyins[$c].”-“ ;

if($isclose==0) unset($pinyins);
if(substr($restr,-1)==”-“) $restr = substr($restr,0,strlen($restr)-1);
return $restr;

红色为新加的

(2)meta的处理

我修改article_article.htm的meta为:

<meta name=”description” content=”{dede:field name=”title”/} {dede:field name=’description’ /}”>
<meta name=”keywords” content=”{dede:field name=’keywords’ /} {dede:field name=”title”/}”>

注意标签之间必须有一个空格,不然后面的就不起作用了

这样修改后,每篇文章的meta都是不同的

list_article.htm的meta我想实现为

<meta name=”description” content=”{dede:field name=’description’ /}”>
<meta name=”keywords” content=”{dede:field name=’keywords’ /}”>

[转载]php实现验证码的识别(中级篇)

mikel阅读(967)

[转载]php实现验证码的识别(中级篇) – ugg的专栏 – CSDN博客.

在上篇文章 <php实现验证码的识别 (初级篇 ) > 中,讲了如何识别简单的验证,这里的简单只的是验证码有数字和字母组成,格式统一,每次 出现位置固定。这篇文章将继续深入研究识别验证码,这次识别的目标是,验证码有字符和数字组成,验证码存在旋转(可能左右都旋转),位置不固定,存在字符 与字符之间的粘连,且验证码有更强的干扰素。这篇文章讲解的方法,并不是万能的解决方案,并且提供代码不能直接解决你的问题,这里仅仅是方法,具体需求读 者自己解决,需要说明的是,识别验证码与具体的编程语言无关,这里只是使用 php 语言实现,使用这里介绍的方法,你可以使用任何语言实现。

这篇文章逐步讲解识别验证码过程中的各个步骤。


如上图,随后的讲解我们都围绕此图展开。
一:拿到一个验证码的,第一眼我们首先要做的工作是,二值化。把验证码的部分用
1 表示,背景部分用 0 表示出来,识别方法很简单,我们打印出验证码正张图片的 RGB ,然后分析其规律即可,通过 RGB 码,我们很容易分辨出上面这张图片的 R 值大于 120 G B 的值小于 80 ,所以依据这个规则我们很容易把上面的图片二值化。再看初级篇中识别的两张图

刚看上去,感觉很复杂。验证码的图片每次背景色都不相同,且不是单色,各个验证码数字的颜色每次也各不相同。貌似很难二值化,其实我们打印出其 RGB 值很容易就发现。无论验证数字颜色如何变化,该数字的 RGB 值总有一个值小于 125 ,所以通过如下判断

$rgbarray[‘red’] < 125 || $rgbarray[‘green’]<125|| $rgbarray[‘blue’] < 125

我们就很容易分辨出哪里是数字,哪里是背景。

我们能够找到这些规律的因素是,在制作验证码的干扰素时,为了使干扰素不影响数字的显示效果,必须使用干扰素的 RGB 和数字 RGB 相互独立,互不干扰。只要懂得这个规律,我们就很容易实现二值化。

我们找到的 120 80 125 等阈值,可能和实际的 RGB 有出入,所以,有时二值化后,会有部分地方出现 1 ,对于验证码上固定位置显示数字,这种干扰没有太大意义。但是对于验证码位置不确定的图片来说,在我们切割字符时,很可能造成干扰。所以,在二值化后要进行去噪出来。

二:接下来我们进行第二个步骤,出噪。出燥的原理很简单,就是把孤立的有效的值去掉,如果噪点比较高,要求的效率也比较高的话,这里面也有很多工作要做。幸好这里我们不要求这么高深,我们使用最简单的方法就可以,如果一个点为 1 则判断这个点的上下左右上左上右下左下右 8 个方位上数字是否为 1 ,如果不为 1 ,就认为是一个燥点,直接设置为 1 即可。

如上图所示,我们使用此方法很容易发现红色方框部分的 1 为燥点,直接设置为 1 即可。

在判断时我们使用了一个技巧,有时候的噪点可能是两个连续的 1 ,所以我们

$num = 0;
if($data[$i][$j] == 1)
{
// 上
if(isset($data[$i-1][$j])){
$num = $num + $data[$i-1][$j];
}
// 下
if(isset($data[$i+1][$j])){
$num = $num + $data[$i+1][$j];
}
// 左
if(isset($data[$i][$j-1])){
$num = $num + $data[$i][$j-1];
}
// 右
if(isset($data[$i][$j+1])){
$num = $num + $data[$i][$j+1];
}
// 上左
if(isset($data[$i-1][$j-1])){
$num = $num + $data[$i-1][$j-1];
}
// 上右
if(isset($data[$i-1][$j+1])){
$num = $num + $data[$i-1][$j+1];
}
// 下左
if(isset($data[$i+1][$j-1])){
$num = $num + $data[$i+1][$j-1];
}
// 下右
if(isset($data[$i+1][$j+1])){
$num = $num + $data[$i+1][$j+1];
}
}
if($num == 0){
$data[$i][$j] = 0;
}

我们计算这个点的 8 个方向上的值之和,最后我们判断他们的和是否小于特定的阈值
三:经过去噪后,我们就得到干净的二值化的数据,接下来要做的就是切割字符了。切割字符的方法有很多种,这里我采用最简单的一种,先垂直方向切割成为字符,然后在水平方向去掉多于的
0000 ,如下图

第一步切割红线部分,第二步切割蓝线部分,这样就可以得到独立的字符了。但是像下面这种情况


按上面的方法会把
dw 字符切割成一个字符,这是错误的切割,所以这里我们涉及到粘连字符的切割。
四:粘连字符切割,制作验证码时,规则字符的粘连很容易分割开,如果字符本身有缩放,变形就很难处理,经过分析,我们可以发现,上面的字符粘连属于很简 单的方式,只是规则字符的粘连,所以处理这种情况,我们也使用很简单的处理方式。当完成分割操作后,我们不能马上确定分割的部分就为一个字符,要进行验 证,验证的关键因素就是,切割下来的字符的宽是否大于阈值,这个阈值的取舍标准是,一个字符无论怎么旋转变形都不会大于这个阈值,所以,如果我们切割的块 大于这个阈值,就可以认为这是一个粘连字符;如果大于两个阈值之和,就认为是三个字符粘连,以此类推。知道这个规则后,切割粘连字符也就很简单了。如果我 们发现是粘连字符块,直接平分这个块为两个或者多个新的块就可以。当然为了更好的还原字符,我一般都采用平分
+1 -1 对字符块的部分进行适当的补充。
五:经过上面四个步骤,我们就可以提取出比较纯的字符块了,接下来要做就是匹配字符了。对于旋转字符的特征码建立,有很多种方法,这里就不做深入研究了。我这里使用的最简单的方式,为所有字符的所有情况建立匹配库,所以在我提供的代码种增加了
study 操作,其目的就是,先有人手工识别图片的验证码,然后通过 study 方法,写入特征码库。这样写入的图片数据越多,验证识别的准确行也就越高。
好了,经过以上步骤,我们基本上可以识别现在互联网上大部分的验证码,这里我们都是使用的最简单的方法,没有使用任何
OCR 知识。这些方法,应该属于非 OCR 领域的顶峰了,要想识别更加复杂的验证码,那就需要更多的 OCR 知识了。有机会的话,我会在高级篇中一一做介绍。
下面是一些容易识别的验证码,希望引起网站管理者的重视。


制作验证码的一些建议
对于识别验证码的程序来说,最难得部分是验证字符的切割和特征码的建立,而国内很多程序员只做验证码时,总是喜欢在验证码加很多干扰素,干扰线,影响效果不说,还达不到很好的效果;所以,要想使自己验证码难于本识别,只做下面两点就够了

1
:字符粘连,最好所有的字符都有粘连的部分;
2
:不要使用规格字符,验证码的各个部分使用不同比例的缩放或者旋转。
只要做到这两点,或者这两点的变形,识别程序就很难识别。我们看看,
yahoo google 的验证码就知道,白字黑底,却很难被识别。

Goole:

yahoo:


源文件下:点击下载
作者
: 逸学堂( ugg
转帖请注明:http://blog.csdn.net/ugg/archive/2009/03/09/3972368.aspx

[转载]php实现验证码的识别(初级篇)

mikel阅读(1004)

[转载]php实现验证码的识别(初级篇) – ugg的专栏 – CSDN博客.

近期研究一些突破验证码方面的知识,记录下来。一方面算是对这几天学习知识的总结帮助自己理解;另一方面希望对研究这方面的技术同学有所帮助;另外 也希望引起网站管理者的注意,在提供验证码时多些考虑进去。由于刚刚接触这方面的知识,理解比较浅显,有错误再所难免,欢迎拍砖。
验证码的作用: 有效防止某个黑客对某一个特定注册用户用特定程序暴力破解方式进行不断的登陆尝试。其实现代的验证码一般是防止机器批量注册的,防止机器批量发帖回复。目前,不少网站为了防止用户利用机器人自动注册、登录、灌水,都采用了验证码技术。
所谓验证码,就是将一串随机产生的数字或符号,生成一幅图片,图片里加上一些干扰象素(防止OCR),由用户肉眼识别其中的验证码信息,输入表单提交网站验证,验证成功后才能使用某项功能。
我们最常见的验证码
1,四位数字,随机的一数字字符串,最原始的验证码,验证作用几乎为零。
2,随机数字图片验证码。图片上的字符比较中规中矩,有的可能加入一些随机干扰素,还有一些是随机字符颜色,验证作用比上一个好。没有基本图形图像学知识的人,不可破!
3,各种图片格式的随机数字+随机大写英文字母+随机干扰像素+随机位置。
4,汉字是注册目前最新的验证码,随机生成,打起来更难了,影响用户体验,所以,一般应用的比较少。
简单起见,我们这次说明的主要对象是第2种类型的,我们先看几种网上比较常见的这种验证码的图片.

(不知道怎么搞的,CSDN又不能上传图片了,我把这四种图片放到下载包中了,可以下载下来对比察看)
这四种样式,基本上能代表2中所提到的验证码类型,初步看起来第一个图片最容易破解,第二个次之,第三个更难,第四个最难。
真实情况那?其实这三种图片破解难度相同。
第一个图片,最容易,图片背景和数字都使用相同的颜色,字符规整,字符位置统一。
第二个图片,看似不容易,其实仔细研究会发现其规则,背景色和干扰素无论怎么变化,验证字符字符规整,颜色相同,所以排除干扰素非常容易,只要是非字符色素全部排除即可。
第三个图片,看似更复杂,处理上面提到背景色和干扰素一直变化外,验证字符的颜色也在变化,并且各个字符的颜色也各不相同。看似无法突破这个验证码,本篇文章,就一这种类型验证码为例说明,第四个图片,同学们自己搞。
第四个图片,除了第三个图片上提到的特征外,又在文字上加了两条直线干扰率,看似困难其实,很容易去掉。
验证码识别一般分为以下几个步骤:
1. 取出字模
2. 二值化
3. 计算特征
4. 对照样本
1:取出字模
识别验证码,毕竟不是专业的OCR识别,并且,由于各个网站的验证码各不相同,所以,最常见的方法就是就是建立这个验证码的特征码库。去字模时,我们需要多下载几张图片,使这些图片中,包括所有的字符,我们这里的字母只有图片,所以,只要收集到包括0-9的图片即可。
2:二值化
二值化就是把图片上的验证数字上每个象素用一种数字表示1,其他部分用0表示。这样就可以计算出每个数字字模,记录下这些字模来,当作key即可。
3:计算特征
把要识别的图片,进行二值化,得到图片特征。
4:对照样本
把步骤3种的图片特征码和验证码的字模进行对比,得到验证图片上的数字。
使用目前这种方法,对验证码的识别基本上可以做到100%。
通 过以上步骤,您可能说了,并没有发现如何取出干扰素啊!其实取出干扰素的方法很简单,干扰素的一个重要特征是,不能影响验证码的显示效果,所以制作干扰素 时它的RGB可能低于或者高于某个特定值,比如我给的例子中的图片,干扰素的RGB各项值是不会超过125的,所以,这样我们就很容易去掉干扰素了。
php代码

    < ?php  
    define('WORD_WIDTH',9);  
    define('WORD_HIGHT',13);  
    define('OFFSET_X',7);  
    define('OFFSET_Y',3);  
    define('WORD_SPACING',4);  
    class valite  
    {  
        public function setImage($Image)  
        {  
            $this->ImagePath = $Image;  
        }  
        public function getData()  
        {  
            return $data;  
        }  
        public function getResult()  
        {  
            return $DataArray;  
        }  
        public function getHec()  
        {  
            $res = imagecreatefromjpeg($this->ImagePath);  
            $size = getimagesize($this->ImagePath);  
            $data = array();  
            for($i=0; $i < $size&#91;1&#93;; ++$i)  
            {  
                for($j=0; $j < $size&#91;0&#93;; ++$j)  
                {  
                    $rgb = imagecolorat($res,$j,$i);  
                    $rgbarray = imagecolorsforindex($res, $rgb);  
                    if($rgbarray&#91;'red'&#93; < 125 || $rgbarray&#91;'green'&#93;&lt;125  
                    || $rgbarray&#91;'blue'&#93; < 125)  
                    {  
                        $data&#91;$i&#93;&#91;$j&#93;=1;  
                    }else{  
                        $data&#91;$i&#93;&#91;$j&#93;=0;  
                    }  
                }  
            }  
            $this->DataArray = $data;  
            $this->ImageSize = $size;  
        }  
        public function run()  
        {  
            $result="";  
            // 查找4个数字  
            $data = array("","","","");  
            for($i=0;$i&lt;4;++$i)  
            {  
                $x = ($i*(WORD_WIDTH+WORD_SPACING))+OFFSET_X;  
                $y = OFFSET_Y;  
                for($h = $y; $h < (OFFSET_Y+WORD_HIGHT); ++ $h)  
                {  
                    for($w = $x; $w < ($x+WORD_WIDTH); ++$w)  
                    {  
                        $data&#91;$i&#93;.=$this->DataArray[$h][$w];  
                    }  
                }  
                  
            }  
            // 进行关键字匹配  
            foreach($data as $numKey => $numString)  
            {  
                $max=0.0;  
                $num = 0;  
                foreach($this->Keys as $key => $value)  
                {  
                    $percent=0.0;  
                    similar_text($value, $numString,$percent);  
                    if(intval($percent) > $max)  
                    {  
                        $max = $percent;  
                        $num = $key;  
                        if(intval($percent) > 95)  
                            break;  
                    }  
                }  
                $result.=$num;  
            }  
            $this->data = $result;  
            // 查找最佳匹配数字  
            return $result;  
        }  
        public function Draw()  
        {  
            for($i=0; $i< $this->ImageSize[1]; ++$i)  
            {  
                for($j=0; $j< $this->ImageSize[0]; ++$j)  
                {  
                    echo $this->DataArray[$i][$j];  
                }  
                echo "\n";  
            }  
        }  
        public function __construct()  
        {  
            $this->Keys = array(  
            '0'=>'000111000011111110011000110110000011110000011110000011110000011110000011110000011110000011011000110011111110000111000',  
            '1'=>'000111000011111000011111000000011000000011000000011000000011000000011000000011000000011000000011000011111111011111111',  
            '2'=>'011111000111111100100000110000000111000000110000001100000011000000110000001100000011000000110000000011111110111111110',  
            '3'=>'011111000111111110100000110000000110000001100011111000011111100000001110000000111000000110100001110111111100011111000',  
            '4'=>'000001100000011100000011100000111100001101100001101100011001100011001100111111111111111111000001100000001100000001100',  
            '5'=>  
           '111111110111111110110000000110000000110000000111110000111111100000001110000000111000000110100001110111111100011111000',  
            '6'=>'000111100001111110011000010011000000110000000110111100111111110111000111110000011110000011011000111011111110000111100',  
            '7'=>'011111111011111111000000011000000010000000110000001100000001000000011000000010000000110000000110000001100000001100000',  
            '8'=>'001111100011111110011000110011000110011101110001111100001111100011101110110000011110000011111000111011111110001111100',  
            '9'=>'001111000011111110111000111110000011110000011111000111011111111001111011000000011000000110010000110011111100001111000',  
        );  
        }  
        protected $ImagePath;  
        protected $DataArray;  
        protected $ImageSize;  
        protected $data;  
        protected $Keys;  
        protected $NumStringArray;  
    }  
    ?>  

我做了一个例子,你可以从这里下载 下载
破解完成上面的验证码,我们就可以使用snoopy(比curl要轻量,所以我喜欢)来模拟浏览器器,访问网站了。

[转载]Predator:比微软Kinect更强的视频追踪算法-来自捷克博士论文

mikel阅读(907)

[转载]Predator:比微软Kinect更强的视频追踪算法-来自捷克博士论文 – CSDN.NET – CSDN资讯.

boycott (haha):刚刚看到了这个用来演示一种新的物体跟踪的算法的视频,它是Zdenek Kalal博士论文里的一部分。Zdenek Kalal是英国萨里大学的一个捷克学生。他演示的是他的神奇的精确定位系统,这个系统几乎可以跟踪镜头里的任何物体,只要你能看见它,并把它选中。它能 做很多神情的事情。在这个视频中,他演示了通过摄像机拍摄他的手指、把他的手指选做目标。系统于是就能精确的跟踪他的手指的动作。更令人惊奇的是,这个系 统能够通过分析物体的运动来完善跟踪算法。你能在很短的时间里教会它跟踪你的手指、面孔或在高速公路上狂颠的轿车。有了这套系统,我们几乎真的可以实 现”Minority Report“那样的人机界面。就像微软Xbox的Kinect那样,而这个效果更好。

Kalal有12个视频来演示他的这套算法都能做什么。只要你有一个好的摄像头,把这个软件装到计算机上、平板电脑上或手机里,它就能精确的定位跟 踪你的前额上的一个点、你的指尖、或你的眼睛。你把摄像头放到门外,它就能自动识别是你认识的人来了,或警告你这是个陌生人。人们不用通过手就能简单的操 控计算机。这项技术应用前景广泛。

你可以从萨里大学的网站找到这个程序的代码,它是免费的。Kalal被授予了“Technology Everywhere”奖学金作为嘉奖。http://info.ee.surrey.ac.uk/Personal/Z.Kalal/tld.html

非常精彩的视频演示:请点击下图

产品介绍

Key Features

  • ● Input: video stream from single monocular camera, bounding box defining the object
  • ● Output: object location in the stream, object model
  • ● Implementation: Matlab + C, single thread, no GPU
  • ● No offline training stage
  • ● Real-time performance on QVGA video stream
  • ● Dependence on OpenCV library (single function)
  • ● Ported to Windows, Mac OS X and Linux
  • ● Illumination invariant features

Free Version(免费源码可从Github下载)

TLD can be downloaded for testing in a chosen application. We provide a precompiled demo (Windows) and a source code that is released under GPL version 3.0. In short, it means that any distributed project that includes or links any portion of TLD source code has to be released with the source code under the GPL version 3.0 license or later.

Commercial Version

A license has to be purchased for using TLD in a commercial project. The licencing is managed by the IP owner, the University of Surrey and the fee is subject to negotiation. Please contact the University of Surrey for further information.

More Information

MITBBS网友评论

lalaphin (orpheus):MIT一直在研究这玩意儿。我早就说过了,微软做kinect最终目标并不是游戏业,而是作为将来windows应用的探路石。

kz80 (雨过天晴):不错, 这学生很能下工夫. kinect也是差不多原理.光线暗了肯定就不能用了。

zlike (最终幻想):我觉得他这个没解决最关键的问题:what to track?object tracking/recognition的一个难点是如何对凭空冒出来的一副图象中判断“哪些”发生了变化(因为所有像素都有变化),而不是对预先选好 的一个小区域进行跟踪。如果他这个没有那个选取的步骤,而是直接能识别移动的“有效”物体,那就可以和kinnect媲美了。

[转载]如何写HtmlHelper的扩展方法。

mikel阅读(975)

[转载]如何写HtmlHelper的扩展方法。 – 斯年余芳 – 博客园.

写了一个ButtonHelper,我将这个方法封在Gqq.Common.dll中。在其他的网站引用中,如何能够实现智能感知呢?
分析了半天才知道,要在web.config(如果用Razor,有两个)中配置pages->namespace节点才可以。
<pages pageBaseType=”System.Web.Mvc.WebViewPage”>
<namespaces>
<add namespace=”System.Web.Mvc” />
<add namespace=”System.Web.Mvc.Ajax” />
<add namespace=”System.Web.Mvc.Html” />
<add namespace=”System.Web.Routing” />
<add namespace=”Gqq.Common.Helper” />
</namespaces>
</pages>
<pages>
<namespaces>
<add namespace=”System.Web.Helpers” />
<add namespace=”System.Web.Mvc” />
<add namespace=”System.Web.Mvc.Ajax” />
<add namespace=”System.Web.Mvc.Html” />
<add namespace=”System.Web.Routing” />
<add namespace=”System.Web.WebPages” />
<!–如果缺少了这个配置,那么在aspx页面中需要使用 @ Import来进行导入,如果多个页面需要使用这个,
(同样 @ Register 可以代替controls)
则最好在web.config中进行配置–>
<add namespace=”GqqMvcWeb.Message” />
<add namespace=”Gqq.Common.Helper” />
</namespaces>
</pages>

这样,在Razor界面中,就可以使用@Html.Button()来构造一个Button了。