vbscript ADO stream charset output - vbscript

My webhook is receiving POST request (aplication/JSON) from a 360Dialog (whatsapp) API with escaped Unicode characters like this: \u05db\u05e0\u05e1\u05d2\u05db\u05d9. It should be Hebrew letters.
I'm trying to decode that using JavaScript runat server but seems like it is not changing. I found a potential solution in this question's solution but it still saves the un-escaped Unicode into the database.
<script language="javascript" runat="server">
URL = {
decode : function(s){return decodeURIComponent(s.replace(/\+/g, " "))}
}
</script>
<%
rs("smstext")=URL.decode(body2)
%>
The POST request is coming from 360dialog (a Whatsapp API) and hitting my webhook.
the request sends an application/json POST with information of incoming Whatsapp messages.
It seems the POST itself already has the Hebrew in it as \u05e0\u05e1\u05d9\u05d5\u05df i guess i need to figure out how to set the charset for that?
also, this unanswered question seems like my same problem.
I am trying to convert a request.BinaryRead into utf-8.
the output in the database is this: \u05e0\u05e1\u05d9\u05d5\u05df instead of נסיון
I am probably misunderstanding something as the output is not what I expected.
my code is:
<%#LANGUAGE="VBSCRIPT" CODEPAGE="65001"%>
<!--#include virtual="/include/aspjson.asp" -->
<%
If Request.TotalBytes > 0 Then
Dim lngBytesCount
lngBytesCount = Request.TotalBytes
body = BytesToStr(Request.BinaryRead(lngBytesCount))
Set db = CreateObject("ADODB.Connection")
db.Open "DSN=xxx"
set rs = Server.CreateObject("ADODB.Recordset")
rs.open "SELECT * FROM log_sms", db, 3, 3
rs.addnew
rs("smstext")=body
rs.update
rs.close
End if
Function BytesToStr(bytes)
Dim Stream
Set Stream = Server.CreateObject("Adodb.Stream")
Stream.Type = 1 'adTypeBinary
Stream.Open
Stream.Write bytes
Stream.Position = 0
Stream.Type = 2 'adTypeText
Stream.Charset = "utf-8"
BytesToStr = Stream.ReadText
Stream.Close
Set Stream = Nothing
End Function
%>
If I replace rs("smstext")=body with rs("smstext")="נסיון", the value in the database is saved correctly.

The approach is sound the problem is because the text is escaped in the JSON body you will need to unescape those characters before saving the content to a database.
Would recommend using this particular JSON Parser as it will automatically handle unescaping the characters for you.
Useful Links
Classic ASP Convert Latin Characters to Unicode Escape Strings *(Contains useful information about escaping, which can help with the unescaping aspect).

The solution (thanks to #user692942 comments):
I replaced the aspJSON library I was using with rcdmk/aspJSON. It takes care of decoding escaped characters already and simplified the process.
Since the POST request to my webhook page is in application/JSON a JSON library is required anyways.
to my little understanding, i must use BinaryRead to fetch the data from such a request. And thus have to convert from byte to str.
the working code is as follows:
<%#LANGUAGE="VBSCRIPT" CODEPAGE="65001" LCID="1037"%>
<!--#include virtual="/wa/aspjson.asp" -->
<%
If Request.TotalBytes > 0 Then
Dim lngBytesCount
lngBytesCount = Request.TotalBytes
jsonbyte = Request.BinaryRead(lngBytesCount)
jsonStr = BytesToStr(jsonbyte)
Set JSON = New JSONobject
Set jsn = JSON.Parse(jsonStr)
Set contact = jsn.value("contacts")(0)
set profile = contact.value("profile")
profname = profile.value("name")
wa_id = contact.value("wa_id")
Set message = jsn.value("messages")(0)
from = message.value("from")
id = message.value("id")
timestamp = message.value("timestamp")
mtype = message.value("type")
set text = message.value("text")
body = text.value("body")
End If
Set db = CreateObject("ADODB.Connection")
db.Open "DSN=xxx"
set rs = Server.CreateObject("ADODB.Recordset")
rs.open "SELECT * FROM log_sms", db, 3, 3
rs.addnew
rs("sent")=DateAdd("s", timestamp, DateSerial(1970,1,1))
rs("from")=from
rs("to")="whatsapp"
rs("smstext")=body
rs("result")="received"
rs("msgid")=id
rs("snr")="r"
rs("type")=mtype
rs.update
rs.close
Function BytesToStr(bytes)
Dim Stream
Set Stream = Server.CreateObject("Adodb.Stream")
Stream.Type = 1 'adTypeBinary
Stream.Open
Stream.Write bytes
Stream.Position = 0
Stream.Type = 2 'adTypeText
Stream.Charset = "utf-8"
BytesToStr = Stream.ReadText
Stream.Close
Set Stream = Nothing
End Function

Related

Classic ASP - Cannot Get Request.Form Values from AJAX Post Request

I have a script that is submitting a POST request of a form via AJAX.
When I look at the network tab, it is coming back in the format below, which I cannot read with a standard Request.Form in Classic ASP. I am seeing this server variable added to the page request as well due to the AJAX request: HTTP_X_REQUESTED_WITH = XMLHttpRequest
The form is set up as a simple POST: <form method="post" action="/contact-submit">
I cannot change the script performing the AJAX request to update the content type, etc.
This is the “Request payload” in the response on the network tab below. I have googled for days and cannot figure this out. How do you access this data? I even tried reading it with a file upload script I have via ASPUpload, but Upload.Form("contact_name") does not work either, it's blank as well.
I tried a simple PHP script (I do not know how PHP works, but this script came with script performing the POST as a demo), and calling print_r($_POST) the script passes all the correct info in an array back in the response on network tab. What the heck!!
Does anyone know how to get this data back in Classic ASP?
Thanks so much for the help in advance.
Dennis
-----------------------------254001430938683980861095915686
Content-Disposition: form-data; name="contact_name"
Test Name
-----------------------------254001430938683980861095915686
Content-Disposition: form-data; name="contact_email"
test#test.com
-----------------------------254001430938683980861095915686
Content-Disposition: form-data; name="contact_message"
my message
-----------------------------254001430938683980861095915686--
I worked on a solution to reading the data, this works below. Not sure it is the best / least expensive way to do this, but it works!
Thanks to everyone for the help / tips. If anyone has a better way to parse the response above, I'm all ears :)
<%
Function BytesToStr(bytes)
Dim Stream
Set Stream = Server.CreateObject("Adodb.Stream")
Stream.Type = 1 'adTypeBinary
Stream.Open
Stream.Write bytes
Stream.Position = 0
Stream.Type = 2 'adTypeText
Stream.Charset = "iso-8859-1"
BytesToStr = Stream.ReadText
Stream.Close
Set Stream = Nothing
End Function
If Request.TotalBytes > 0 Then
Dim lngBytesCount, post
lngBytesCount = Request.TotalBytes
post = BytesToStr(Request.BinaryRead(lngBytesCount))
End If
Response.ContentType = "text/plain"
sContentType = Replace(Request.ServerVariables("CONTENT_TYPE"),"multipart/form-data; boundary=---------------------------","")
arrPost = Split(post,"-----------------------------" & sContentType)
For i = 0 to UBound(arrPost)
sVal = Replace(arrPost(i),"Content-Disposition: form-data; name=","")
arrVal = Split(sVal,Chr(10),1)
For a = 0 to UBound(arrVal)
If Instr(1, arrVal(a), "contact_name") <> 0 Then
Response.Write GetValue(arrVal(a), "contact_name")
End If
If Instr(1, arrVal(a), "contact_message") <> 0 Then
Response.Write GetValue(arrVal(a), "contact_message")
End If
Next
Next
Function GetValue(f_FullString, f_FieldName)
fieldval = Replace(f_FullString, """" & f_FieldName & """","")
'response.Write "_" & fieldval & "_<Br>"
arrVal1 = Split(fieldval,Chr(10),1)
For b = 0 to UBound(arrVal1)
newval = arrVal1(b)
newval = Left(newval,Len(newval) - 2)
newval = Right(newval,Len(newval) - 6)
'For z = 1 to Len(newval)
' CurrChar = Mid(newval, z, 1)
' Response.Write Asc(CurrChar) & "<bR>"
'Next
Next
GetValue = newval
End Function
%>
UPDATE:
This is another solution if you have ASPUpload installed. I tried this last night, but forgot to add Upload.Save (which would have saved me 4hours of work --- UGGGGGHHHH).
'http://www.aspupload.com/manual_memory.html
Set Upload = Server.CreateObject("Persits.Upload")
Upload.Save
Name = Upload.Form("contact_name")
Response.Write Name

How to set Japanese characters(UTF-8) in VBScript variables

I have a script where I need to set some Japanese text to a variable. But since vbscript is not supporting japanese texts, it get converted to some garbled text like トコジャパンã‹ã‚‰ã®æ–°è¦æ³¨æ–‡. My actual japanese text is トコジャパンからの新規注文.
My script will look like below
dim emlObj
set emlObj = CreateObject("EMailObject")
emlObj.Subject = "Train - New Orders From Costco Japan | コストコジャパンからの新規注文"
emlObj.Body = "Some japanese body text"
emlObj.Send()
I do not have any other options like storing this text in file or db and process in some other scripts as of now. since this script will be used by our customers and they will set their expected email body text. We'll use them for sending it as a mail.
I've also tried ADODB.Steam but that works only when reading the text from file.
Can someone please suggest a way to set the japanese text in vbscript?.
Edit:
To put a clarity on what i really needed.
I want to hard-code a japanese text to a variable in VBScripts.
You can use this solution:
Dim objStream, body, subject
Set objStream = CreateObject("ADODB.Stream")
objStream.CharSet = "utf-8"
objStream.Open
objStream.WriteText "Subject in Japanese"
objStream.SaveToFile "C:\Subject.txt", 2
objStream.Close
objStream.Open
objStream.WriteText "Body in Japanese"
objStream.SaveToFile "C:\body.txt", 2
objStream.Close
objStream.CharSet = "utf-8"
objStream.Open
objStream.LoadFromFile "C:\Body.txt"
body = objStream.ReadText()
objStream.Close
objStream.CharSet = "utf-8"
objStream.Open
objStream.LoadFromFile "C:\Subject.txt"
subject = objStream.ReadText()
objStream.Close
' Now body is stored in body variable and subject is in subject now do anything with them
IMPORTANT: Since you are not using ADODB.Stream to load your content, then be sure to save your actual VBScript file as UTF-16 LE encoding. Your script may optionally benefit from a Unicode byte-order-mark (BOM) header, as well -- depending upon how the VBScript engine and EmailObject respond.
Once the VBScript file is in the proper encoding, this script works fine for me:
With CreateObject("CDO.Message")
With .Configuration.Fields
.Item("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2
.Item("http://schemas.microsoft.com/cdo/configuration/smtpserver") = "smtp.somemailserver.net"
.Item("http://schemas.microsoft.com/cdo/configuration/smtpconnectiontimeout") = 10
.Item("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25
.Update
End With
.BodyPart.Charset = "utf-8"
.BodyPart.ContentTransferEncoding = "base64"
.TextBody = "コストコジャパンからの新規注文"
.TextBodyPart.Charset = "utf-8"
.HTMLBody = "<p>コストコジャパンからの新規注文</p>"
.HTMLBodyPart.Charset = "utf-8"
.From = "me#somemailserver.net"
.To = "you#somemailserver.net"
.Subject = "Train - New Orders From Costco Japan | コストコジャパンからの新規注文"
.Send()
End With
Note: I am using CDO.Message above, not EmailObject.
Hope this helps.

Valid response causes "Subcript out of range"

I've got a classic ASP application that contacts a database and receives a valid response but then crashes with
Error Number 9: Subscript out of range
after exiting the IF block the db call is made in. What's odd is that the same code is currently working in production. As far as I can tell they're configured identically (but I suspect there's a subtle difference that's causing this issue) and have identical code bases.
What I want to know is:
Where is this array that I'm supposedly attempting to reach a non-existent index of? I don't see it and the error gives no line number. Is there a chance something is not working correctly in the adodb library?
Perhaps this is a common problem having to do with a certain patch and my particular db connection library? Have you had a similar experience?
How do I troubleshoot a problem that doesn't immediately present itself? Should I just start putting troubleshooting statements in the library?
Explanation of what's happening in the code: When the cookie "click" is received err.number is 0. When the cookie "bang" is received the err.number is 9. It then crashes with that error at the end of the IF block.
<%#Language="VBSCRIPT"%>
<% Server.ScriptTimeout = 150 %>
<%
On Error resume Next
%>
<!--#include file="adovbs.inc"-->
<!--#INCLUDE FILE="DBConn.asp"-->
<!--#INCLUDE FILE="ErrorHandler.asp"-->
<%
'Application Timeout Warning
sessionTimeout = 20
advanceWarning = 5
jsTimeout = (sessionTimeout - advanceWarning) * 60000
'If the users session has expired
If Session("USERNAME") = "" or Session("USERNAME") = NULL Then
Response.Redirect("default.asp")
End If
'If the user has just changed their password. Prompt them that it was successfully changed
If Request("changePasswd") = "true" Then
Response.Write("<script language='Javascript'>alert('Your Password Has been Successfully Changed!');</script>")
End If
Dim connection, cmd, objRS, latestDate, lastDateJPMC, firstDateJPMC, lastDateWACH, firstDateWACH, lastDateWFB, firstDateWFB, accountCount
Function calConvertDate(theDate)
Dim yr, mn, dy, dtSplit
dtSplit = Split(theDate,"/")
yr = dtSplit(2)
mn = dtSplit(0)
dy = dtSplit(1)
if Len(mn) = 1 then mn = "0" & mn
if Len(dy) = 1 then dy = "0" & dy
calConvertDate = "[" & yr & "," & mn & "]"
End Function
set connection = Server.CreateObject("adodb.connection")
connection.Open DBConn
connection.CommandTimeout = 60
set connection = Server.CreateObject("adodb.connection")
connection.Open DBConn
connection.CommandTimeout = 60
'Get Earliest & Latest Date in Database
If Err.Number = 0 Then
Response.Cookies("CLICK")=Err.number
Set cmd = Server.CreateObject("ADODB.Command")
With cmd
Set .ActiveConnection = connection
.CommandText = "CIRS_Admin.spGetLatestDate"
.CommandType = adCmdStoredProc
set objRS = .Execute
End With
latestDate = calConvertDate(objRS("latestDate"))
Response.Cookies("latestdate")=objRS("latestDate")
objRS.Close
Set objRS = Nothing
Response.Cookies("BANG")=Err.number
End If
To debug, please add a statement like
Response.Write (objRS("latestDate"))
before the line
latestDate = calConvertDate(objRS("latestDate"))
so you can see if (for example) the date returned from the server has "-" as separator instead of "/" or if an empty value is returned.
After understanding what is causing the problem you can solve it
1.Where is this array that I'm supposedly attempting to reach a non-existent index of? I don't see it and the error gives no line number. Is there a chance something is not working correctly in the adodb library?
This is your array:
yr = dtSplit(2)
mn = dtSplit(0)
dy = dtSplit(1)
What's odd is that the same code is currently working in production. As far as I can tell they're configured identically (but I suspect there's a subtle difference that's causing this issue) and have identical code bases.
May be you have different regional settings?
I strongly suggest to you use better error handling.
Internal Server Error 500 w/ IIS Log

Foreign character encoding issue with CSV download

I am using UTF8 encoding for ASP pages. I want to implement a CSV download functionality for my website. Below is my response setup
With Response
.Buffer = true
.Expires = 0
.Clear
.Charset = "UTF-8"
.CodePage = 65001
.AddHeader "Content-Type", "text/html;charset=UTF-8"
.AddHeader "content-encoding", "UTF-8"
.AddHeader "content-disposition", "attachment; filename=""AgedDebtors.csv"""
End With
Encoding is set for response headers still i am getting encoded foreign characters in resulting CSV. Tried few things for this but was not able to get it right. Please let me know what i am missing here
Set stream = CreateObject("ADODB.Stream")
stream.Open
stream.Type = 2 'text
stream.Position = 0
stream.Charset = "utf-8"
stream.WriteText str
you may want to save the converted stream into a new file, so write this
stream.SaveToFile filename, 2
And to close the stream use
stream.Close

How can I strip the element using vbscript and display in message box?

I would like to find the price with 2 year contract and display it in a message box. Sofar I have:
Dim MyPage
Dim Price
Set MyPage=CreateObject("Microsoft.XMLDOM")
MyPage.load("http://www.verizonwireless.com/b2c/store/controller?item=phoneFirst&action=viewPhoneDetail&selectedPhoneId=5723")
Wscript.Sleep 2000
Set Price = MyPage.getElementsByTagName("span")
For Each Elem In Price
MsgBox(Elem.firstChild.nodeValue)
Next
I understand that I am completely wrong, but I don't even know where to start. I love writing simple programs like this, but I just need help getting started. Any ideas will help!
Here a better version, uses the HTMLFile object
Dim HTMLDoc, XML, URL, table
Set HTMLDoc = CreateObject("HTMLFile")
Set XML = CreateObject("MSXML2.XMLHTTP")
URL = "http://www.verizonwireless.com/b2c/store/controller?item=phoneFirst&action=viewPhoneDetail&selectedPhoneId=5723"
With XML
.Open "GET", URL, False
.Send
HTMLDoc.Write .responseText
End With
Set spans = HTMLDoc.getElementsByTagName("span")
for each span in spans
WScript.Echo span.innerHTML
next
'=><SPAN>Set Location</SPAN>
'=>Set Location
'=><SPAN>Submit</SPAN>
'=>Submit
'=>Connect with us
the control you use is for reading XML documents, you need something like this
'Create an xmlhttp object, the string depends on the version that is installed
'on your pc could eg also be "Msxml2.ServerXMLHTTP.5.0"
Set xmlhttp = CreateObject("Microsoft.XMLHTTP")
xmlhttp.Open "GET", "http://admin:pasword#10.0.0.2/doc/ppp.htm", False
xmlhttp.Send
text=xmlhttp.responseText
wscript.echo text
Set xmlhttp = Nothing
Run a search in your registry for XMLHTTP to get the right string/version for the identifier.
To get the tag from the html you can use the following
text = "blabla <span>this is what i need</span> bla bla<span>second item</span> end"
function getElementsByTagName(sTextToSeachIn, tag)
answer = ""
separator = ""
set oRegExpre = new RegExp
with oRegExpre
.IgnoreCase = true
.Global = true
.MultiLine = True
.Pattern = "<" & tag & ">(.*?)</" & tag & ">"
end with
set oColMatches = oRegExpre.Execute(sTextToSeachIn)
for each match in oColMatches
answer = answer & separator & match.subMatches(0)
separator = "|" 'use something that's not in the spancontents
next
if separator <> "" then
getElementsByTagName = split(answer, separator)
else
getElementsByTagName = array()
end if
end function
for each tag in getElementsByTagName(text, "span")
wscript.echo tag
next
'=>this is what i need
'=>second item
There are better techniques and certainly better languages than vbscript to do this, i suggest to take a look at Ruby which exels in such things.
Alex, in response to your comment about getting a cookie and running a javascript in HTMLFile, here a ruby script i found, hopes it helps you at some point, it reads in a page, passes it to the HTLMFile object and in that DOM executes a remote javascript file. It also gives you an idea of the combined power of activeX and Ruby.
require "win32ole"
$jsxpath_uri = "http://svn.coderepos.org/share/lang/javascript/javascript-xpath/trunk/release/javascript-xpath-latest-cmp.js"
uri, xpath = "http://gist.github.com/gists", "//div[#class='info']/span/a"
http = WIN32OLE.new('MSXML2.XMLHTTP')
http.Open "GET", uri, false
http.Send
text = http.responseText
dom = WIN32OLE.new("htmlfile")
dom.Write(text)
dom.parentWindow.eval(open($jsxpath_uri){|f| f.read })
items = dom.evaluate(xpath, dom, nil, 7, nil)
len = items.snapshotLength
(0...len).each do |i|
item = items.snapshotItem(i)
puts item.innerHTML
end

Resources