My Insert Stored Procedure works, but I get this error ADODB.Recordset error '800a0e78' - asp-classic

This site has been very useful in helping resolved many unknowns. Thank you. Now I have one unknown that I have not been able to locate an answer to.
The error is:
ADODB.Recordset error '800a0e78'
Operation is not allowed when the object is closed.
I’m using:
ASP Classic
MS SQL Server 2000
In ASP there is a <textarea> within a “form” to insert notes, when notes are inserted and the submit button is pushed the stored procedure insert the note into the note table datetimestamp it and add the logon user. That is doing exactly what it is to do. Additionally in ASP there is a <table> that populates with the note, datetimestamp and logon user with the other previous entries. That also is doing exactly what it is to do.
The above mentioned error occurs when the submit button is pressed, by hitting the browsers back button when the error page shows up, then refreshing the page the <textarea> is cleared and note, datetimetime, and logon user display in the <table>
ASP Classic page:
Dim rsAccountNote
<form name="Accountnote" method="post" action="/admin/xt_Accountnote.asp">
<td>
<b>Add Note:</b><br />
<textarea type="text" name="notes" value="" rows="7" cols="43" style="resize: none;"></textarea><br />
<input type="submit" value="Add new note"/>
</td>
<table>
<tr>
<td>
<b>Read Notes:</b>
</td>
</tr>
<%
set rsAccountNote = DBConn.Execute("SELECT AccountNotes, LogonUser_Id, dtAccountNotedatetime FROM AccountNotes WHERE AccountId = " & rsAccount("AccountId"))
rsAccountNote.Sort="dtAccountNotedatetime DESC"
Do While Not rsAccountNote.EOF
%>
<tr>
<td>
Added <%=rsAccountNote("dtAccountNotedatetime")%> by <%=rsAccountNote("LogonUser_Id")%>
</td>
</tr>
<tr>
<td>
<b>Note: </b> <%=rsAccountNote("AccountNotes")%>
</td>
</tr>
<%
rsAccountNote.MoveNext
Loop
Set rsAccountNote = Nothing
%>
</tr>
</td>
</tr>
</table>
</form>
ASP Classic xt_page:
<%
Dim rsAccount
Dim iAccount
Dim LogonUser_id
Dim AccountNotes
sSQL = "exec spApp_UpdateAccountNotes " & _
"#iAccount = " & Trim(Request("Account_id")) & ", " & _
"#AccountNotes = " & prepString(Request("AccountNotes")) & ", " & _
"#LogonUser_id = " & prepString(Request("Logon_User"))
Call resultQuery(DBConn, rsAccount, sSQL, "", true)
Response.Redirect("/Account_admin/accountinfo.asp?account_id=" & Trim(Request("account_id")))
%>
Stored procedure:
CREATE PROCEDURE spApp_UpdateAccountNotes
(
#iAccount int,
#LogonUser_id varchar (50),
#AccountNotes varchar(5000)
)
AS
SET NOCOUNT ON
insert AccountNotes
(
AccountId,
LogonUser_Id,
AccountNotes
)
values
(
#iAccount,
#LogonUser_Id,
#AccountNotes
)
GO

Try using a Command object to execute the SP as parameterised query. This solves the more serious problem of your code being open to a SQL Injection attack.
In fact your first page is also open to attack, you should use a command object there also.
Possibly the real source of your problem is that resultQuery tries to generate and do something with a recordset from the SP which doesn't return a result set, its only an insert. Perhaps resultQuery just isn't the thing to call in this case. An ADODB Command object and Execute would be all that is needed.

Related

How to pass value parameter in url that cannot excecute directly in url?

So i have this program that sending notification value to other page and show the notification, but the problem is you can edit the value in the url,
If lngErrNo <> 0 Then
response.write "Error while update Product."
response.end
Else
v_strMsg = "Edit Kelipatan Jumlah Pesanan Berhasil!"
Response.Redirect "global_notification.asp?strMsg=" & v_strMsg
End If
the problem is you can edit v_strMsg in url for the example abc.com/global_notification.asp?strMsg= "anything you can edit the value here", and the display page is look like this
<body>
<table class="1" width=70% cellpadding="0" cellspacing="0">
<tr>
<td colspan="3" background="images/bgtable.gif"><div align="left" class="fontwhiteheader13">
ATTENTION!!</div>
</td>
</tr>
<tr>
<td valign="top"><table width=100% height="360" cellpadding="2" cellspacing="2" bgcolor="white">
<tr>
<td align=center class="fontblueheader13"><%=Request.QueryString("strMsg")%>
</td>
</tr>
</table></td></tr></table>
</body>
any possible way to sending the value without changing it to POST metod? i try htmlEncode but v_strMsg still can be edited in url, any suggestion?
You need a signed URL.
A signed URL includes a digital signature that proves the request was generated by the server.
The first thing you need to do is create a secret key:
' Generate your own key from:
' https://www.allkeysgenerator.com/Random/Security-Encryption-Key-Generator.aspx
Const secret_key = "G+KbPeShVmYq3s6v9y$B&E)H#McQfTjW"
In this example it's a 256 bit key.
You also need a hashing function:
hash.asp
<%
' Might as well store the secret key constant in this file:
Const secret_key = "G+KbPeShVmYq3s6v9y$B&E)H#McQfTjW"
Function Hash(ByVal Input, HashAlgorithm)
' Select the System.Security.Cryptography value.
Select Case uCase(HashAlgorithm)
Case "MD5"
HashAlgorithm = "MD5CryptoServiceProvider"
Case "SHA1"
HashAlgorithm = "SHA1CryptoServiceProvider"
Case "SHA2","SHA256"
HashAlgorithm = "SHA256Managed"
Case "SHA384"
HashAlgorithm = "SHA384Managed"
Case "SHA5","SHA512"
HashAlgorithm = "SHA512Managed"
Case Else
HashAlgorithm = "SHA1CryptoServiceProvider"
End Select
' Convert the input to bytes if not already.
If NOT VarType(Input) = 8209 Then
Dim utf8 : Set utf8 = Server.CreateObject("System.Text.UTF8Encoding")
Input = utf8.GetBytes_4(Input)
Set utf8 = Nothing
End If
' Perform the hash.
Dim hAlg : Set hAlg = Server.CreateObject("System.Security.Cryptography." & HashAlgorithm)
Dim hEnc : Set hEnc = Server.CreateObject("MSXML2.DomDocument").CreateElement("encode")
hEnc.dataType = "bin.hex"
hEnc.nodeTypedValue = hAlg.ComputeHash_2((Input))
Hash = hEnc.Text
Set hEnc = Nothing
Set hAlg = Nothing
End Function
%>
Now you're ready to sign your URL with a digital signature.
' Be sure to include "hash.asp"
' Your message:
v_strMsg = "Edit Kelipatan Jumlah Pesanan Berhasil!"
' A unix timestamp:
v_uts = DateDiff("s","1970-01-01 00:00:00",Now())
' NOTE: Your servers timezone should be set to UTC to generate a true unix timestamp,
' but it doesn't really matter, as long as "global_notification.asp" is on the same
' server, or a server set to the same timezone as the page you're generating the
' signature from.
' Now we create the signature as so:
v_signature = Hash(v_strMsg & v_uts & secret_key,"SHA256")
' Finally, redirect to "global_notification.asp"
Response.Redirect "global_notification.asp?strMsg=" & Server.URLEncode(v_strMsg) & "&ts=" & v_uts & "&signature=" & v_signature
Example redirect:
global_notification.asp?strMsg=Edit+Kelipatan+Jumlah+Pesanan+Berhasil%21&ts=1612794802&signature=61016c0a0460902cc4a19f092dcbb4fd818aa9c88d2631e087868253e73983da
Now to validate the signature on global_notification.asp:
<!--#include file = "hash.asp" -->
<%
Dim v_strMsg, v_uts, v_signature, v_uts_now
v_strMsg = Request.QueryString("strMsg")
v_uts = Request.QueryString("ts")
v_signature = Request.QueryString("signature")
' Do some basic validation first.
If v_signature = "" Then
Response.Write "Missing Signature"
Response.End()
ElseIf v_uts = "" Then
Response.Write "Missing Timestamp"
Response.End()
ElseIf NOT Len(v_signature) = 64 Then
Response.Write "Invalid Signature"
Response.End()
ElseIf NOT (IsNumeric(v_uts) AND Len(v_uts) = 10) Then
Response.Write "Invalid Timestamp"
Response.End()
End If
' Validate the signature. To do this, we simply recreate what we're expecting the signature
' to be, and compare it to the one being passed.
If NOT Hash(v_strMsg & v_uts & secret_key,"SHA256") = v_signature Then
Response.Write "Invalid Signature"
Response.End()
End If
' Now let's set an expiration period for the link, say 30 seconds? (or 86400 seconds for a day, 604800 for a week etc).
v_uts = Int(v_uts) + 30
v_uts_now = DateDiff("s","1970-01-01 00:00:00",Now())
If v_uts_now >= v_uts Then
Response.Write "Expired Link"
Response.End()
End If
' At this point, everything is good.
' Go ahead and display the message:
%>
<body>
<table class="1" width="70%" cellpadding="0" cellspacing="0">
<tr>
<td colspan="3" background="images/bgtable.gif"><div align="left" class="fontwhiteheader13"> ATTENTION!!</div></td>
</tr>
<tr>
<td valign="top"><table width="100%" height="360" cellpadding="2" cellspacing="2" bgcolor="white">
<tr>
<td align=center class="fontblueheader13"><%=v_strMsg%></td>
</tr>
</table></td>
</tr>
</table>
</body>
Now if you try and change the message (or the timestamp) you'll get an Invalid Signature error. The only way to generate a valid working link is to know the secret key, which of course is hidden.

ADODB, VBScript, ASP, SELECT not working with WHERE

My SELECT statement works until I add a WHERE parameter.
When I have the WHERE parameter added I get a 500 error.
Again, This works correctly unless I add a WHERE parameter to the select statement.
<html>
<body>
<%
set conn=Server.CreateObject("ADODB.Connection")
conn.Provider="Microsoft.Jet.OLEDB.4.0"
Dim db_path
Dim db_dir
db_dir = Server.MapPath("/private") & "\"
db_path = db_dir & "Database.mdb"
conn.Open db_path
set rs=Server.CreateObject("ADODB.recordset")
sql="SELECT DISTINCT Group, Finish FROM Parts WHERE Group = 'Exhaust'"
rs.Open sql, conn
%>
<table border="1" width="100%">
<%response.write(sql)%>
<tr>
<%for each x in rs.Fields
response.write("<th>" & x.name & "</th>")
next%>
</tr>
<%do until rs.EOF%>
<tr>
<%for each x in rs.Fields%>
<td><%Response.Write(x.value)%></td>
<%next
rs.MoveNext%>
</tr>
<%loop
rs.close
conn.close%>
</table>
</body>
</html>
I fixed it.
It works if I change the select statement to this:
sql="SELECT DISTINCT Group, Finish FROM Parts WHERE (((Group)='Exhaust'));"

classic asp verify the server result

I am trying to check or unchecked the check-boxes depends upon the data results that comes from server. But I cannot use below code correctly where I am doing wrong?
<%
Dim AFTER_SAVE, IN_VIEW, Y
Dim SQL, Data
SQL = " SELECT code, name, value FROM mytable WHERE code = '" & User & "'"
Data = Data(SQL)
%>
<%If IsArray(Data) Then%>
<%If ((Data(1,0) = "AFTER_SAVE") AND (Data(2,0) = "Y")) Then %>
document.getElementById("chkSave").checked == true;
<%End If%>
<% If ((Data(1,0) = "IN_VIEW") AND (Data(2,0) = "Y")) Then %>
document.getElementById("chkVIEW").checked == true;
<%End If%>
<%End If%>
You're trying to combine server-side code with client-side code in a very strange way. Sometimes, it's necessary to do that (i.e. use server-side VBScript to write client-side Javascript), but if I'm understanding your intent correctly, it's not needed here.
Basically, if this is actually a classic ASP page, then somewhere on that page you're generating the checkboxes in question. So all you need to do is put your database call somewhere before that, and then when you generate the checkboxes, you can output a checked='checked', or not, depending.
Note that I have no clue what Data = Data(SQL) is supposed to mean. There's no way for it to be valid VBScript code - parentheses are for arrays, but a string is not a valid array index, and then to assign it to itself like that? Anyway, I'm ignoring that part.
<html>
<head>
<%
Dim AFTER_SAVE, IN_VIEW
Dim SQL, RS, Conn
Dim User
'...blah blah blah, give a value to User, set up your DB connection, etc. etc....
SQL = "SELECT code, name, [value] FROM mytable WHERE code = '" & User & "'"
'- ("value" is a reserved keyword in SQL, hence the brackets)
Set RS = Server.Createobject("ADODB.Recordset")
RS.Open SQL, Conn, 1, 2 '- this is rather handwavy and unlikely to actually
'- work as-is; use the options and connection methods that make sense for you
Do Until RS.EOF
'- I have no idea how your data is set up; this may make no sense.
'- The idea is, read the checkbox states from your database, and
'- stick them in variables for later reference.
Select Case RS("name")
Case "AFTER_SAVE" AFTER_SAVE = RS("value")
Case "IN_VIEW" IN_VIEW = RS("value")
End Select
RS.Movenext
Loop
RS.Close
Set RS = Nothing
%>
</head>
<body>
<form method="post" action="myformhandler.asp">
<!-- form fields and stuff -->
<input type="checkbox" name="chkSave" id="chkSave" <%
If AFTER_SAVE = "Y" Then Response.Write "checked='checked'"
%> value="Y"><label for="chkSave">After save</label>
<input type="checkbox" name="chkView" id="chkView" <%
If IN_VIEW = "Y" Then Response.Write "checked='checked'"
%> value="Y"><label for="chkView">In view</label>
<!-- more form stuff -->
</form>
</body>
</html>

How to display data from stored procedure in a drop down in Classic ASP?

This is related to Classic ASP code.
A page fetches data for a particular ProjectCode.
There is a general text field which shows the Site-Location for selected Project-Code. I want to change it to drop down, so that a user can change the Site-Location from options available (fetched from DB) and then save it. Also, on page load the Site-Location of Project-Code for that particular entry should be selected.
I have added following code to my Page, but it doesn't work(definately I am new to classic ASP).
strSQL = "SP_GET_SiteLocation"
Set rsSiteList = RunSQLQuery(strSQL)
'show the list
If Not rsSiteList.EOF Then
Do While NOT rs.EOF
SiteLocationList= SiteLocationList & "<option value="">" & rs("LOCATION") & "</option>"
rs.MoveNext
Also, on click of save button, i have to send the selected drop down value to update query.
You use a wrong name for the recordset variable..
You named it rsSiteList but you use it as rs
Do While NOT rsSiteList.EOF
SiteLocationList= SiteLocationList & "<option value="">" & rsSiteList("LOCATION") & "</option>"
rsSiteList.MoveNext
Update
You are building a string with all the options ..
you should write it in the page at some point.. response.write(SiteLocationList)
or write the <options> directly to the page..
<select name="somename"><%
Do While NOT rsSiteList.EOF
%>
<option value=""><%=rsSiteList("LOCATION")%></option>
<%
rsSiteList.MoveNext
Loop
%>
</select>
update 2
Not sure why you do not want to print the options as you read them from the recordset but prefer to make a huge string instead and print that at the end ... it is the same thing but much more cleaner ..
The following should select the location that matches the rsReqDetails("AppReqSiteID")
<td>
<%
strSQL="SP_EPAPM_GET_SiteLocation"
Set rsSiteList=RunSQLQuery(strSQL)
selectedValue = rsReqDetails("AppReqSiteID")
If Not rsSiteList.EOF Then
Do While NOT rsSiteList.EOF
loc = rsSiteList("LOCATION")
if loc <> selectedValue then
optionOpen = "<option>"
else
optionOpen = "<option selected=""selected"">"
end if
optionClose = "</option>"
SiteLocationList=SiteLocationList & optionOpen & rsSiteList("LOCATION") & optionClose
rsSiteList.MoveNext
Loop
End If
%>
<select id="SiteLocationList" NAME="SiteLocationList">
<%response.write(SiteLocationList)%>
</select>
</td>
In general you need to watch the nesting of html as it can mess everything up. Also you need to read a little on the interactions between ASP and HTML ...
You almost got it, you're missing the "select" tag:
strSQL = "SP_GET_SiteLocation"
Set rsSiteList = RunSQLQuery(strSQL)
'show the list
If Not rsSiteList.EOF Then %>
<select><%Do While NOT rs.EOF SiteLocationList= SiteLocationList & "<option value="">" & rs("LOCATION") & "</option>"
rs.MoveNext %>
</select>

ASP How do I insert a username into a table?

I'm struggling with my code below, I'm reading the logged on users username and trying to insert their name into a SQL table called licenses, the table contains 2 columns 1 contains license numbers the other is all nulls at the moment but a username should be inserted along side one when this page loads. Currently the page just loops constantly and nothing is inserted into the table. The user inside connection1.asp does have read/write access to the database.
Any ideas? Thanks
<%#LANGUAGE="VBSCRIPT" LCID=1033%>
<%
aName = Split(Request.ServerVariables("LOGON_USER"), "\")
user = aName(UBound(aName))
user = UCase(user)
Erase aName
%>
<!--#include file="Connections/connection1.asp" -->
<%
Dim Recordset1
Dim Recordset1_numRows
Set Recordset1 = Server.CreateObject("ADODB.Recordset")
Recordset1.ActiveConnection = MM_connection1_STRING
Recordset1.Source = "SELECT * FROM Licenses2 WHERE userid = '" & user & "';"
Recordset1.Open()
%>
<HTML><HEAD></HEAD>
<BODY leftmargin="5" onLoad="setTimeout('reloadFunction()',500000)">
<% Do While NOT Recordset1.EOF %>
<% strUserName =(Recordset1.Fields.Item("userid").Value)%>
<% response.write strUserName %>'s Serial Number:
<% strSerial =(Recordset1.Fields.Item("serial").Value)%>
<% response.write strSerial %>
<% Recordset1.movenext %>
<% loop %>
<%
If strUserName = user then
'record found do nothing
'response.write "user found"
else
adoCon.Execute = "SET ROWCOUNT 1; UPDATE Licenses2 SET userid = '" & user & "' WHERE userid = 'NULL';"
Response.AddHeader "Refresh", "3"
End if
%>
</BODY>
</HTML>
<%
Recordset1.Close()
Set Recordset1 = Nothing
Set Recordset2 = Nothing
%>
If the user is NOT found, should you be doing an INSERT instead of UPDATE?
If the UPDATE is correct, change the last NULL ... remove the quotes. Right now you are comparing a STRING value of 'NULL' instead of the value NULL and it should be IS NULL
SET ROWCOUNT 1; UPDATE Licenses2 SET userid = '" & user & "' WHERE userid IS NULL;
Also, see if you can comment out the <BODY ... > tag and create a new one without the RELOADFUNCTION and see if that makes a difference.
Lastly, read up on SQL Injection because your code is prone to Injection attacks. Search on StackOverflow.com for SQL Injection and you will find plenty of explanations, examples and cures.
Check if LOGON_USER is actually returning any data. If you have IIS security set to 'Anonymous' access then this will not be populated with anything.
Your code would also be potentially prone to SQL injection attacks.

Resources