Can you turn off case-sensitivity in VBScript strings? - asp-classic

I'm pretty sure the answer to this is no. I know that I can write
if lcase(strFoo) = lcase(request.querystring("x")) then...
or use inStr, but I just want to check there isn't some undocumented setting buried in the registry or somewhere that makes the content of VBScript strings behave consistently with the rest of the scripting language!
Thanks
Dan

There is a StrComp function which allows performing a case-insensitive comparison of two strings by passing vbTextCompare as the third argument. The main documentation doesn't make that obvious, but it is discussed in this Hey, Scripting Guy article.
For example:
If StrComp(strFoo, Request.QueryString("x"), vbTextCompare) = 0 Then ...
However, in practice, I use LCase or UCase way more than StrComp for case-insensitive string comparisons because it's more obvious to me.

No. Depending on the function the option may be there (InStr for example) as an optional parameter, but for just straight comparison, there is no global option.
One little known option that can be handy is if you have a list of strings and you want to see if a string is in that list:
Dim dicList : Set dicList = CreateObject("Scripting.Dictionary")
Dim strTest
dicList.CompareMode = 0 ' Binary ie case sensitive
dicList.Add "FOO", ""
dicList.Add "BAR", ""
dicList.Add "Wombat", ""
strTest = "foo"
WScript.Echo CStr(dicList.Exists(strTest))
Set dicList = CreateObject("Scripting.Dictionary")
dicList.CompareMode = 1 ' Text ie case insensitive
dicList.Add "FOO", ""
dicList.Add "BAR", ""
dicList.Add "Wombat", ""
strTest = "foo"
WScript.Echo CStr(dicList.Exists(strTest))

I doubt the existence of such an option since if there were something like that and you use it, you'll lose the ability to compare strings in a case sensitive manner.

Related

How to generate MD5 using VBScript in classic ASP?

I need to generate an MD5 in my application.
I've tried google but only find PHP code for MD5. I need to connect to a client system that validates using MD5 hash but their code is in PHP, mine is in Classic ASP using VBScript.
My server is .Net supported so I cannot use the PHP script. Is there any such MD5 code for VBScript in Classic ASP?
Update 2017-02-21 - Now with added HMACSHA256 for JWTs
Update 2016-07-05 - Now with added SHA1 and SHA256
Right, for all of you who have been struggling with this (like myself) and want to know, it is possible!
The following code is split up into several functions so that you can either MD5/sha1/sha256 a string, or a file.
I borrowed the functions GetBytes and BytesToBase64 from another stackexchange, and the code within stringToUTFBytes is based on another stackexchange.
function md5hashBytes(aBytes)
Dim MD5
set MD5 = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider")
MD5.Initialize()
'Note you MUST use computehash_2 to get the correct version of this method, and the bytes MUST be double wrapped in brackets to ensure they get passed in correctly.
md5hashBytes = MD5.ComputeHash_2( (aBytes) )
end function
function sha1hashBytes(aBytes)
Dim sha1
set sha1 = CreateObject("System.Security.Cryptography.SHA1Managed")
sha1.Initialize()
'Note you MUST use computehash_2 to get the correct version of this method, and the bytes MUST be double wrapped in brackets to ensure they get passed in correctly.
sha1hashBytes = sha1.ComputeHash_2( (aBytes) )
end function
function sha256hashBytes(aBytes)
Dim sha256
set sha256 = CreateObject("System.Security.Cryptography.SHA256Managed")
sha256.Initialize()
'Note you MUST use computehash_2 to get the correct version of this method, and the bytes MUST be double wrapped in brackets to ensure they get passed in correctly.
sha256hashBytes = sha256.ComputeHash_2( (aBytes) )
end function
function sha256HMACBytes(aBytes, aKey)
Dim sha256
set sha256 = CreateObject("System.Security.Cryptography.HMACSHA256")
sha256.Initialize()
sha256.key=aKey
'Note you MUST use computehash_2 to get the correct version of this method, and the bytes MUST be double wrapped in brackets to ensure they get passed in correctly.
sha256HMACBytes = sha256.ComputeHash_2( (aBytes) )
end function
function stringToUTFBytes(aString)
Dim UTF8
Set UTF8 = CreateObject("System.Text.UTF8Encoding")
stringToUTFBytes = UTF8.GetBytes_4(aString)
end function
function bytesToHex(aBytes)
dim hexStr, x
for x=1 to lenb(aBytes)
hexStr= hex(ascb(midb( (aBytes),x,1)))
if len(hexStr)=1 then hexStr="0" & hexStr
bytesToHex=bytesToHex & hexStr
next
end function
Function BytesToBase64(varBytes)
With CreateObject("MSXML2.DomDocument").CreateElement("b64")
.dataType = "bin.base64"
.nodeTypedValue = varBytes
BytesToBase64 = .Text
End With
End Function
'Special version that produces the URLEncoded variant of Base64 used in JWTs.
Function BytesToBase64UrlEncode(varBytes)
With CreateObject("MSXML2.DomDocument").CreateElement("b64")
.dataType = "bin.base64"
.nodeTypedValue = varBytes
BytesToBase64UrlEncode = replace(replace(replace(replace(replace(.Text,chr(13),""),chr(10),""),"+", "-"),"/", "_"),"=", "")
End With
End Function
Function GetBytes(sPath)
With CreateObject("Adodb.Stream")
.Type = 1 ' adTypeBinary
.Open
.LoadFromFile sPath
.Position = 0
GetBytes = .Read
.Close
End With
End Function
These can be used as follows:
BytesToBase64(md5hashBytes(stringToUTFBytes("Hello World")))
Produces: sQqNsWTgdUEFt6mb5y4/5Q==
bytesToHex(md5hashBytes(stringToUTFBytes("Hello World")))
Produces: B10A8DB164E0754105B7A99BE72E3FE5
For SHA1:
bytesToHex(sha1hashBytes(stringToUTFBytes("Hello World")))
Produces: 0A4D55A8D778E5022FAB701977C5D840BBC486D0
For SHA256:
bytesToHex(sha256hashBytes(stringToUTFBytes("Hello World")))
Produces: A591A6D40BF420404A011733CFB7B190D62C65BF0BCDA32B57B277D9AD9F146E
To get the MD5 of a file (useful for Amazon S3 MD5 checking):
BytesToBase64(md5hashBytes(GetBytes(sPath)))
Where sPath is the path to the local file.
And finally, to create a JWT:
'define the JWT header, needs to be converted to UTF bytes:
aHead=stringToUTFBytes("{""alg"":""HS256"",""typ"":""JWT""}")
'define the JWT payload, again needs to be converted to UTF Bytes.
aPayload=stringToUTFBytes("{""sub"":""1234567890"",""name"":""John Doe"",""admin"":true}")
'Your shared key.
theKey="mySuperSecret"
aSigSource=stringToUTFBytes(BytesToBase64UrlEncode(aHead) & "." & BytesToBase64UrlEncode(aPayload))
'The full JWT correctly Base 64 URL encoded.
aJWT=BytesToBase64UrlEncode(aHead) & "." & BytesToBase64UrlEncode(aPayload) & "." & BytesToBase64UrlEncode(sha256HMACBytes(aSigSource,stringToUTFBytes(theKey)))
Which will produce the following valid JWT:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.7ofvtkn0z_pTl6WcqRTxw-4eSE3NqcEq9_3ax0YcuIQ
Here is a readable and downloadable version of MD5 as VBS script:
https://github.com/Wikinaut/md5.vbs
It's the code from http://chayoung.tistory.com/entry/VBScript-MD5 (thank you for this unique piece of code).
Thanks for all the links provided above, they were useful but this one I found really did the job if anybody ever needs it.
VBScript-MD5
I have no idea if this code even works, since I have no way of testing it. However, it seems to be what you are asking for.
http://www.bullzip.com/md5/vb/md5-vb-class.htm
Here is an interesting article by Jeff Attwood on hashes. He has some important things to say about MD5:
http://www.codinghorror.com/blog/2012/04/speed-hashing.html
First of all, thank you SgtWilko! :)
Based on your collected information, I've done one function for all (not for base64/Files).
Your code was very useful for me, but I was searching for a more PHP alike (simple) Function to deal with plain text and with a more explicit code.
Edited:
Based on the issue How to hash a UTF-8 string in Classic ASP, I come up with the ADODB.Stream solution. You can now use non-English characters.
Edited:
Parameter PlainText was changed to Target.
You can now use the HMAC versions.
Just use the Target parameter as an array.
Target(0) = PlainText
Target(1) = SharedKey
Thank you again SgtWilko ;)
Announcing the first SHA1 collision (Google Security Blog) February 23, 2017.
With this function you can hash the plain text into:
MD5, RIPEMD160, SHA1, SHA256, SHA384, SHA512, HMACMD5, HMACRIPEMD160, HMACSHA1, HMACSHA256, HMACSHA384 and HMACSHA512
If you need more you can find it in: System.Security.Cryptography Namespace
Function Hash(HashType, Target)
On Error Resume Next
Dim PlainText
If IsArray(Target) = True Then PlainText = Target(0) Else PlainText = Target End If
With CreateObject("ADODB.Stream")
.Open
.CharSet = "Windows-1252"
.WriteText PlainText
.Position = 0
.CharSet = "UTF-8"
PlainText = .ReadText
.Close
End With
Set UTF8Encoding = CreateObject("System.Text.UTF8Encoding")
Dim PlainTextToBytes, BytesToHashedBytes, HashedBytesToHex
PlainTextToBytes = UTF8Encoding.GetBytes_4(PlainText)
Select Case HashType
Case "md5": Set Cryptography = CreateObject("System.Security.Cryptography.MD5CryptoServiceProvider") '< 64 (collisions found)
Case "ripemd160": Set Cryptography = CreateObject("System.Security.Cryptography.RIPEMD160Managed")
Case "sha1": Set Cryptography = CreateObject("System.Security.Cryptography.SHA1Managed") '< 80 (collision found)
Case "sha256": Set Cryptography = CreateObject("System.Security.Cryptography.SHA256Managed")
Case "sha384": Set Cryptography = CreateObject("System.Security.Cryptography.SHA384Managed")
Case "sha512": Set Cryptography = CreateObject("System.Security.Cryptography.SHA512Managed")
Case "md5HMAC": Set Cryptography = CreateObject("System.Security.Cryptography.HMACMD5")
Case "ripemd160HMAC": Set Cryptography = CreateObject("System.Security.Cryptography.HMACRIPEMD160")
Case "sha1HMAC": Set Cryptography = CreateObject("System.Security.Cryptography.HMACSHA1")
Case "sha256HMAC": Set Cryptography = CreateObject("System.Security.Cryptography.HMACSHA256")
Case "sha384HMAC": Set Cryptography = CreateObject("System.Security.Cryptography.HMACSHA384")
Case "sha512HMAC": Set Cryptography = CreateObject("System.Security.Cryptography.HMACSHA512")
End Select
Cryptography.Initialize()
If IsArray(Target) = True Then Cryptography.Key = UTF8Encoding.GetBytes_4(Target(1))
BytesToHashedBytes = Cryptography.ComputeHash_2((PlainTextToBytes))
For x = 1 To LenB(BytesToHashedBytes)
HashedBytesToHex = HashedBytesToHex & Right("0" & Hex(AscB(MidB(BytesToHashedBytes, x, 1))), 2)
Next
If Err.Number <> 0 Then Response.Write(Err.Description) Else Hash = LCase(HashedBytesToHex)
On Error GoTo 0
End Function
These can be used as follows:
Hash("sha512", "Hello World")
Produces:
2c74fd17edafd80e8447b0d46741ee243b7eb74dd2149a0ab1b9246fb30382f27e853d8585719e0e67cbda0daa8f51671064615d645ae27acb15bfb1447f459b
Hash("sha256", "Hello World")
Produces:
a591a6d40bf420404a011733cfb7b190d62c65bf0bcda32b57b277d9ad9f146e
Hash("md5", "muñeca")
Produces:
ea07bec1f37f4b56ebe368355d1c058f
Hash("sha512HMAC", Array("Hello World", "Shared Key"))
Produces:
28e72824c48da5a5f14b59246905d2839e7c50e271fc078b1c0a75c89b6a3998746bd8b2dc1764b19d312702cf5e15b38ce799156af28b98ce08b85e4df65b32
There is Javascript code that produces an MD5 checksum. One of them, derived from the Google closure library, is available here.
It's pretty easy to produce a Windows Script Component from the Javascript, then call that component from any COM-enabled language, including VB.
Here's a working example.

Detecting null/empty input from user

How can I check if the user has input a null or empty string in classic-asp? Right now I am have this code.
If Request.Form("productId") == "" Then
'my code here
End If
But its not working.
Classic ASP/VBScript uses one = to check for equality, not two. Another thing you may want to try is
If Request.Form("productid") = "" Then
Code here
End If
It is a mess. Here's what I have found ...
(1) To look for existence in the QS, use if IsEmpty(x)=false (ie, URL?x)
(2) To look for a value in the QS, look for if x <> "" (ie, URL?x=anything)
Good luck!
If IsEmpty(Request.Form("inputPhoneNo")) = False Then
response.Write"<script language=javaScript>alert('Blank Phone Number');</script>"
response.Write"<script language=javascript>history.back()</script>"
Else
End If

Why is this looping infinitely?

So I just got my site kicked off the server today and I think this function is the culprit. Can anyone tell me what the problem is? I can't seem to figure it out:
Public Function CleanText(ByVal str As String) As String
'removes HTML tags and other characters that title tags and descriptions don't like
If Not String.IsNullOrEmpty(str) Then
'mini db of extended tags to get rid of
Dim indexChars() As String = {"<a", "<img", "<input type=""hidden"" name=""tax""", "<input type=""hidden"" name=""handling""", "<span", "<p", "<ul", "<div", "<embed", "<object", "<param"}
For i As Integer = 0 To indexChars.GetUpperBound(0) 'loop through indexchars array
Dim indexOfInput As Integer = 0
Do 'get rid of links
indexOfInput = str.IndexOf(indexChars(i)) 'find instance of indexChar
If indexOfInput <> -1 Then
Dim indexNextLeftBracket As Integer = str.IndexOf("<", indexOfInput) + 1
Dim indexRightBracket As Integer = str.IndexOf(">", indexOfInput) + 1
'check to make sure a right bracket hasn't been left off a tag
If indexNextLeftBracket > indexRightBracket Then 'normal case
str = str.Remove(indexOfInput, indexRightBracket - indexOfInput)
Else
'add the right bracket right before the next left bracket, just remove everything
'in the bad tag
str = str.Insert(indexNextLeftBracket - 1, ">")
indexRightBracket = str.IndexOf(">", indexOfInput) + 1
str = str.Remove(indexOfInput, indexRightBracket - indexOfInput)
End If
End If
Loop Until indexOfInput = -1
Next
End If
Return str
End Function
Wouldn't something like this be simpler? (OK, I know it's not identical to posted code):
public string StripHTMLTags(string text)
{
return Regex.Replace(text, #"<(.|\n)*?>", string.Empty);
}
(Conversion to VB.NET should be trivial!)
Note: if you are running this often, there are two performance improvements you can make to the Regex.
One is to use a pre-compiled expression which requires re-writing slightly.
The second is to use a non-capturing form of the regular expression; .NET regular expressions implement the (?:) syntax, which allows for grouping to be done without incurring the performance penalty of captured text being remembered as a backreference. Using this syntax, the above regular expression could be changed to:
#"<(?:.|\n)*?>"
This line is also wrong:
Dim indexNextLeftBracket As Integer = str.IndexOf("<", indexOfInput) + 1
It's guaranteed to always set indexNextLeftBracket equal to indexOfInput, because at this point the character at the position referred to by indexOfInput is already always a '<'. Do this instead:
Dim indexNextLeftBracket As Integer = str.IndexOf("<", indexOfInput+1) + 1
And also add a clause to the if statement to make sure your string is long enough for that expression.
Finally, as others have said this code will be a beast to maintain, if you can get it working at all. Best to look for another solution, like a regex or even just replacing all '<' with <.
In addition to other good answers, you might read up a little on loop invariants a little bit. The pulling out and putting back stuff to the string you check to terminate your loop should set off all manner of alarm bells. :)
Just a guess, but is this like the culprit?
indexOfInput = str.IndexOf(indexChars(i)) 'find instance of indexChar
Per the Microsoft docs, Return Value -
The index position of value if that string is found, or -1 if it is not. If value is Empty, the return value is 0.
So perhaps indexOfInput is being set to 0?
What happens if your code tries to clean the string <a?
As I read it, it finds the indexChar at position 0, but then indexNextLeftBracket and indexRightBracket both equal 0, you fall into the else condition, and then you insert a ">" at position -1, which will presumably insert at the beginning, giving you the string ><a. The new indexRightBracket then becomes 0, so you delete from position 0 for 0 characters, leaving you with ><a. Then the code finds the <a in the code again, and you're off to the races with an infinite memory-consuming loop.
Even if I'm wrong, you need to get yourself some unit tests to reassure yourself that these edge cases work properly. That should also help you find the actual looping code if I'm off-base.
Generally speaking though, even if you fix this particular bug, it's never going to be very robust. Parsing HTML is hard, and HTML blacklists are always going to have holes. For instance, if I really want to get a <input type="hidden" name="tax" tag in, I'll just write it as <input name="tax" type="hidden" and your code will ignore it. Your better bet is to get an actual HTML parser involved, and to only allow the (very small) subset of tags that you actually want. Or even better, use some other form of markup, and strip all HTML tags (again using a real HTML parser of some description).
I'd have to run it through a real compiler but the mindpiler tells me that the str = str.Remove(indexOfInput, indexRightBracket - indexOfInput) line is re-generating an invalid tag such that when you loop through again it finds the same mistake "fixes" it, tries again, finds the mistake "fixes" it, etc.
FWIW heres a snippet of code that removes unwanted HTML tags from a string (It's in C# but the concept translates)
public static string RemoveTags( string html, params string[] allowList )
{
if( html == null ) return null;
Regex regex = new Regex( #"(?<Tag><(?<TagName>[a-z/]+)\S*?[^<]*?>)",
RegexOptions.Compiled |
RegexOptions.IgnoreCase |
RegexOptions.Multiline );
return regex.Replace(
html,
new MatchEvaluator(
new TagMatchEvaluator( allowList ).Replace ) );
}
MatchEvaluator class
private class TagMatchEvaluator
{
private readonly ArrayList _allowed = null;
public TagMatchEvaluator( string[] allowList )
{
_allowed = new ArrayList( allowList );
}
public string Replace( Match match )
{
if( _allowed.Contains( match.Groups[ "TagName" ].Value ) )
return match.Value;
return "";
}
}
That doesn't seem to work for a simplistic <a<a<a case, or even <a>Test</a>. Did you test this at all?
Personally, I hate string parsing like this - so I'm not going to even try figuring out where your error is. It'd require a debugger, and more headache than I'm willing to put in.

Best Regular Expression for Email Format Validation with ASP.NET 3.5 Validation

I've used both of the following Regular Expressions for testing for a valid email expression with ASP.NET validation controls. I was wondering which is the better expression from a performance standpoint, or if someone has better one.
- \w+([-+.']\w+)*#\w+([-.]\w+)*\.\w+([-.]\w+)*
- ^([0-9a-zA-Z]([-\.\w]*[0-9a-zA-Z])*#([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+[a-zA-Z]{2,9})$
I'm trying avoid the "exponentially slow expression" problem described on the BCL Team Blog.
UPDATE
Based on feedback I ended up creating a function to test if an email is valid:
Public Function IsValidEmail(ByVal emailString As String, Optional ByVal isRequired As Boolean = False) As Boolean
Dim emailSplit As String()
Dim isValid As Boolean = True
Dim localPart As String = String.Empty
Dim domainPart As String = String.Empty
Dim domainSplit As String()
Dim tld As String
If emailString.Length >= 80 Then
isValid = False
ElseIf emailString.Length > 0 And emailString.Length < 6 Then
'Email is too short
isValid = False
ElseIf emailString.Length > 0 Then
'Email is optional, only test value if provided
emailSplit = emailString.Split(CChar("#"))
If emailSplit.Count <> 2 Then
'Only 1 # should exist
isValid = False
Else
localPart = emailSplit(0)
domainPart = emailSplit(1)
End If
If isValid = False OrElse domainPart.Contains(".") = False Then
'Needs at least 1 period after #
isValid = False
Else
'Test Local-Part Length and Characters
If localPart.Length > 64 OrElse ValidateString(localPart, ValidateTests.EmailLocalPartSafeChars) = False OrElse _
localPart.StartsWith(".") OrElse localPart.EndsWith(".") OrElse localPart.Contains("..") Then
isValid = False
End If
'Validate Domain Name Portion of email address
If isValid = False OrElse _
ValidateString(domainPart, ValidateTests.HostNameChars) = False OrElse _
domainPart.StartsWith("-") OrElse domainPart.StartsWith(".") OrElse domainPart.Contains("..") Then
isValid = False
Else
domainSplit = domainPart.Split(CChar("."))
tld = domainSplit(UBound(domainSplit))
' Top Level Domains must be at least two characters
If tld.Length < 2 Then
isValid = False
End If
End If
End If
Else
'If no value is passed review if required
If isRequired = True Then
isValid = False
Else
isValid = True
End If
End If
Return isValid
End Function
Notes:
IsValidEmail is more restrictive about characters allowed then the RFC, but it doesn't test for all possible invalid uses of those characters
If you're wondering why this question is generating so little activity, it's because there are so many other issues that should be dealt with before you start thinking about performance. Foremost among those is whether you should be using regexes to validate email addresses at all--and the consensus is that you should not. It's much trickier than most people expect, and probably pointless anyway.
Another problem is that your two regexes vary hugely in the kinds of strings they can match. For example, the second one is anchored at both ends, but the first isn't; it would match ">>>>foo#bar.com<<<<" because there's something that looks like an email address embedded in it. Maybe the framework forces the regex to match the whole string, but if that's the case, why is the second one anchored?
Another difference is that the first regex uses \w throughout, while the second uses [0-9a-zA-Z] in many places. In most regex flavors, \w matches the underscore in addition to letters and digits, but in some (including .NET) it also matches letters and digits from every writing system known to Unicode.
There are many other differences, but that's academic; neither of those regexes is very good. See here for a good discussion of the topic, and a much better regex.
Getting back to the original question, I don't see a performance problem with either of those regexes. Aside from the nested-quantifiers anti-pattern cited in that BCL blog entry, you should also watch out for situations where two or more adjacent parts of the regex can match the same set of characters--for example,
([A-Za-z]+|\w+)#
There's nothing like that in either of the regexes you posted. Parts that are controlled by quantifiers are always broken up by other parts that aren't quantified. Both regexes will experience some avoidable backtracking, but there are many better reasons than performance to reject them.
EDIT: So the second regex is subject to catastrophic backtracking; I should have tested it thoroughly before shooting my mouth off. Taking a closer look at that regex, I don't see why you need the outer asterisk in the first part:
[0-9a-zA-Z]([-.\w]*[0-9a-zA-Z])*
All that bit does is make sure the first and last characters are alphanumeric while allowing some additional characters in between. This version does the same thing, but it fails much more quickly when no match is possible:
[0-9a-zA-Z][-.\w]*[0-9a-zA-Z]
That would probably suffice to eliminate the backtracking problem, but you could also make the part after the "#" more efficient by using an atomic group:
(?>(?:[0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+)[a-zA-Z]{2,9}
In other words, if you've matched all you can of substrings that look like domain components with trailing dots, and the next part doesn't look like a TLD, don't bother backtracking. The first character you would have to give up is the final dot, and you know [a-zA-Z]{2,9} won't match that.
We use this RegEx which has been tested in-house against 1.5 million addresses. It correctly identifies better than 98% of ours, but there are some formats that I'm aware of that it would error on.
^([\w-]+(?:\.[\w-]+)*)#((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$
We also make sure that there are no EOL characters in the data since an EOL can fake out this RegEx. Our Function:
Public Function IsValidEmail(ByVal strEmail As String) As Boolean
' Check An eMail Address To Ensure That It Is Valid
Const cValidEmail = "^([\w-]+(?:\.[\w-]+)*)#((?:[\w-]+\.)*\w[\w-]{0,66})\.([a-z]{2,6}(?:\.[a-z]{2})?)$" ' 98% Of All Valid eMail Addresses
IsValidEmail = False
' Take Care Of Blanks, Nulls & EOLs
strEmail = Replace(Replace(Trim$(strEmail & " "), vbCr, ""), vbLf, "")
' Blank eMail Is Invalid
If strEmail = "" Then Exit Function
' RegEx Test The eMail Address
Dim regEx As New System.Text.RegularExpressions.Regex(cValidEmail)
IsValidEmail = regEx.IsMatch(strEmail)
End Function
I am a newbie, but I tried the following and it seemed to have limited the ".xxx" to only two occurrences or less, after the symbol '#'.
^([a-zA-Z0-9]+[a-zA-Z0-9._%-]*#(?:[a-zA-Z0-9-])+(\.+[a-zA-Z]{2,4}){1,2})$
Note: I had to substitute single '\' with double '\\' as I am using this reg expr in R.
These don't check for all allowable email addresses according to the email address RFC.
I let MS to do the work for me:
Public Function IsValidEmail(ByVal emailString As String) As Boolean
Dim retval As Boolean = True
Try
Dim address As New System.Net.Mail.MailAddress(emailString)
Catch ex As Exception
retval = False
End Try
Return retval
End Function
For server side validation, I found Phil Haack's solution to be one of the better ones. His attempt was to stick to the RFC:
string pattern = #"^(?!\.)(""([^""\r\\]|\\[""\r\\])*""|"
+ #"([-a-z0-9!#$%&'*+/=?^_`{|}~]|(?<!\.)\.)*)(?<!\.)"
+ #"#[a-z0-9][\w\.-]*[a-z0-9]\.[a-z][a-z\.]*[a-z]$";
Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
return regex.IsMatch(emailAddress);
Details:
http://blog.degree.no/2013/01/email-validation-finally-a-net-regular-expression-that-works/
Just to contribute, I am using this regex.
^([a-zA-Z0-9]+[a-zA-Z0-9._%-]*#(?:[a-zA-Z0-9-]+\.)+[a-zA-Z]{2,4})$
The thing about it is the specifications are changing with each domain extension that is introduced.
You sit here mod your regex, test, test, test, and more testing. You finally get what you "think" is accurate then the specification changes... You update your regex to account for what the new requirements are..
Then someone enters aa#aa.aa and you've done all that work for what? It walks through your fancy regex.. bummer!
You may as well just check for a single #, and a "." and move on. I assure you, you will not get someones email if they do not want to give it up. You'll get garbage or their hotmail account they never check and couldn't care less about.
I've seen in many cases this goes horribly wrong and a client calls up because their own email address is rejected because of a poorly crafted regex check. Which as mentioned shouldn't have even been attempted.
TextBox :-
<asp:TextBox ID="txtemail" runat="server" CssClass="form-control pantxt" Placeholder="Enter Email Address"></asp:TextBox>
Required Filed validator:
<asp:RequiredFieldValidator ID="RequiredFieldValidator9" runat="server" ControlToValidate="txtemail" ErrorMessage="Required"></asp:RequiredFieldValidator>
Regular Expression for email validation :
<asp:RegularExpressionValidator ID="validateemail" runat="server" ControlToValidate="txtemail" ValidationExpression="\w+([-+.']\w+)*#\w+([-.]\w+)*\.\w+([-.]\w+)*" ErrorMessage="Invalid Email"></asp:RegularExpressionValidator>
Use this regular expression for email validation in asp.net

How do I traverse a collection in classic ASP?

I want to be able to do:
For Each thing In things
End For
CLASSIC ASP - NOT .NET!
Something like this?
dim cars(2),x
cars(0)="Volvo"
cars(1)="Saab"
cars(2)="BMW"
For Each x in cars
response.write(x & "<br />")
Next
See www.w3schools.com.
If you want to associate keys and values use a dictionary object instead:
Dim objDictionary
Set objDictionary = CreateObject("Scripting.Dictionary")
objDictionary.Add "Name", "Scott"
objDictionary.Add "Age", "20"
if objDictionary.Exists("Name") then
' Do something
else
' Do something else
end if
Whatever your [things] are need to be written outside of VBScript.
In VB6, you can write a Custom Collection class, then you'll need to compile to an ActiveX DLL and register it on your webserver to access it.
The closest you are going to get is using a Dictionary (as mentioned by Pacifika)
Dim objDictionary
Set objDictionary = CreateObject("Scripting.Dictionary")
objDictionary.CompareMode = vbTextCompare 'makes the keys case insensitive'
objDictionary.Add "Name", "Scott"
objDictionary.Add "Age", "20"
But I loop through my dictionaries like a collection
For Each Entry In objDictionary
Response.write objDictionary(Entry) & "<br />"
Next
You can loop through the entire dictionary this way writing out the values which would look like this:
Scott
20
You can also do this
For Each Entry In objDictionary
Response.write Entry & ": " & objDictionary(Entry) & "<br />"
Next
Which would produce
Name: Scott
Age: 20
One approach I've used before is to use a property of the collection that returns an array, which can be iterated over.
Class MyCollection
Public Property Get Items
Items = ReturnItemsAsAnArray()
End Property
...
End Class
Iterate like:
Set things = New MyCollection
For Each thing in things.Items
...
Next
As Brett said, its better to use a vb component to create collections. Dictionary objects are not very commonly used in ASP unless for specific need based applications.
Be VERY carefully on using VB Script Dictionary Object!
Just discover this "autovivication" thing, native on this object: http://en.wikipedia.org/wiki/Autovivification
So, when you need to compare values, NEVER use a boolen comparison like:
If objDic.Item("varName") <> "" Then...
This will automatically add the key "varName" to the dictionary (if it doesn't exist, with an empty value) , in order to carry on evaluating the boolean expression.
If needed, use instead If objDic.Exists("varName").
Just spend a few days knocking walls, with this Microsoft "feature"...
vbscript-dictionary-object-creating-a-key-which-never-existed-but-present-in-another-object

Resources