Thứ Năm, 10 tháng 5, 2012

CSS Transparency Settings for All Browsers

.transparent {
 /* Required for IE 5, 6, 7 */
 /* ...or something to trigger hasLayout, like zoom: 1; */
 width: 100%; 

 /* Theoretically for IE 8 & 9 (more valid) */
 /* ...but not required as filter works too */
 /* should come BEFORE filter */
 -ms-filter:"progid:DXImageTransform.Microsoft.Alpha(Opacity=50)";

 /* This works in IE 8 & 9 too */
 /* ... but also 5, 6, 7 */
 filter: alpha(opacity=50);

 /* Older than Firefox 0.9 */
 -moz-opacity:0.5;

 /* Safari 1.x (pre WebKit!) */
 -khtml-opacity: 0.5;

 /* Modern!
 /* Firefox 0.9+, Safari 2?, Chrome any?
 /* Opera 9+, IE 9+ */
 opacity: 0.5;
}
 
(http://css-tricks.com/css-transparency-settings-for-all-broswers/) 

Thứ Năm, 3 tháng 5, 2012

Why won't QueryString values work with Server.Execute / Server.Transfer?

The Server.Execute and Server.Transfer commands are fairly useful replacements for #includes. However, as many people have pointed out, if you use a QueryString value, you receive this error:

Server object error 'ASP 0235 : 80004005'
Server.Transfer Error
/.asp, line
Invalid URL form or fully-qualified absolute URL was used. Use relative URLs.

or
Server object error 'ASP 0231 : 80004005'
Server.Execute Error
/.asp, line
Invalid URL form or fully-qualified absolute URL was used. Use relative URLs.

Even when your URL *IS* relative (removing the QueryString value makes the page function properly).

Unfortunately, Microsoft has yet to recognize this officially as a bug. So in the meantime, you must rely on session variables or database entries to retrieve any information you would like to pass to the target page.

However, keep in mind that if you had QueryString values coming in to the calling page, you can access those without difficulty in the target page. So as an example, let's say a.asp calls b.asp, and a.asp was called with a.asp?x=1&y=2:

<%
    ' a.asp
    Server.Execute("b.asp")
%>

<%
    ' b.asp
    Response.Write(Request.QueryString("x"))
    Response.Write("
")
    Response.Write(Request.QueryString("y"))
%>

You will see the results printed in the browser, because b.asp still has access to the ServerVariables context.

If you really need to pass *new* QueryString information into b.asp and you can't change that file or change the call to a.asp to include that new information, you can make a.asp redirect to itself with the new information. A simple logic tree will ensure that you only suffer the hit when the new information is not included.

<%
    ' a.asp
    if Request.QueryString("foo") = "" then
        Response.Redirect "a.asp?foo=bar"
    else
        Server.Execute("b.asp")
    end if
%>

<%
    ' b.asp
    Response.Write(Request.QueryString("foo"))
%>

You could also do this using a new go-between page instead of adding logic to a.asp.

(http://classicasp.aspfaq.com/general/why-won-t-querystring-values-work-with-server-execute/server-transfer.html)

How do I make my ASP page pause or 'sleep'?

There is a free component that will help you do this; it is called WaitFor 1.0 and is available at ServerObjects Inc.

If you are using SQL Server (or have access to one), you can try out the following script (adapted from a post by Pierre W):

<%

    Set conn = CreateObject("ADODB.Connection")
    conn.Open ""

    ' indicate a number of seconds, up to 59
    sleep = 10

    ' make sure timeout doesn't expire!
    conn.commandTimeout = sleep + 5

    ' if you neede more than 59 seconds, you will need to adjust the SQL:
    sql = "WAITFOR DELAY '00:00:" & right(clng(sleep),2) & "'"

    Response.Write(now & "")
    conn.Execute sql,,129
    Response.Write(now & "
")

    conn.close:     Set conn = Nothing
%>

Some people will suggest a loop like this:

<%
Response.Buffer = true

Function WaitFor(SecDelay,ShowMsg)
    timeStart = Timer()
    timeEnd = timeStart + SecDelay

    Msg = "Timer started at " & timeStart & "
"
    Msg = Msg & "Script will continue in "

    i = SecDelay
    Do While timeStart < timeEnd
        If i = Int(timeEnd) - Int(timeStart) Then
        Msg = Msg & i
        If i <> 0 Then Msg = Msg & ", "
        If ShowMsg = 1 Then Response.Write Msg
%>

<%         Response.Flush() %>

<%
        Msg = ""
        i = i - 1
        End if
        timeStart = Timer()
    Loop
    Msg = "...
Slept for " & SecDelay & " seconds (" & _
        Timer() & ")"
    If ShowMsg = 1 Then Response.Write Msg
End Function

Call WaitFor(20,0)
Call WaitFor(3,1)
%>

This is BAD, BAD news. If you can't immediately see why this is a problem, run it and watch task manager:


Look at the page faults, and look at the CPU usage for w3wp.exe. And this is on a dual-processor workstation; it literally pegs a single-CPU server at 99% running through that loop.

(http://classicasp.aspfaq.com/general/how-do-i-make-my-asp-page-pause-or-sleep.html)

How do I read the contents of a remote web page?

You can include static txt and HTML files from remote servers by using a component (such as AspHTTP, ASPTear 1.50, or VB's built in InetCtrls) to parse the remote URL's content.

You can also try this method out; it was tested with the MSXML objects which are installed with Windows 2000. You should make sure you have the latest versions of MSXML and XML Core Services (see MSXML Downloads). If you download the newer version, take special note of the new ProgID you should be using -- MSXML 4.0 now supports side-by-side installation, which means the ProgID below will actually use the older version.

<%
    url = "http://www.espn.com/main.html"
    set xmlhttp = CreateObject("MSXML2.ServerXMLHTTP")
    xmlhttp.open "GET", url, false
    xmlhttp.send ""
    Response.write xmlhttp.responseText
    set xmlhttp = nothing
%>

And here it is in JavaScript:


If you use a URL that doesn't exist, or you are behind a firewall that blocks certain web sites, or the site is behind a firewall that blocks traffic to port 80 / 443, or you are using a proxy server, or the site requires authentication, you will receive this error:

msxml4.dll (0x80072EE7)
Server name or address could not be resolved

To correct, you will have to figure out which of the issue(s) is standing in your way, and discuss workarounds with your or their network administrator(s).

Don't forget that if your remote page has relative image URLs, or style sheets, or JavaScript files, or frames, or links, it won't work perfectly when ported to your server(s). To overcome this, you'll want to add a BASE HREF tag to keep all the images coming from the correct location. For example, the above code (which gets all the text from espn.com, but is formatted weird and doesn't function 100% as intended), is modified only slightly to work correctly:

<%
    url = "http://www.espn.com/main.html"

    ' add a BASE HREF tag
    Response.write ""

    set xmlhttp = CreateObject("MSXML2.ServerXMLHTTP")
    xmlhttp.open "GET", url, false
    xmlhttp.send ""
    Response.write xmlhttp.responseText
    set xmlhttp = nothing
%>

For information on increasing or decreasing the time allowed for the XMLHTTP objects to retrieve a response from a remote server, see Article #2407.

If you need to POST data you can so by adding a header that tells the receiver you're sending FORM data:

<%
    url = "http://www.espn.com/main.html"
    set xmlhttp = CreateObject("MSXML2.ServerXMLHTTP")
    xmlhttp.open "POST", url, false
    xmlhttp.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
    xmlhttp.send "x=1&y=2"
    Response.write xmlhttp.responseText
    set xmlhttp = nothing
%>

Another thing you may want to do, going back to the original script, is make sure the server is there! If not, you can display a message... and you can customize it to display whether the server was not found at all, or if the server was found but you got a bad response (e.g. a 404 Page Not Found). Note that if you do not need to parse the content of the remote web page, that using the HEAD method here is far more efficient than using GET or POST... since only the headers are retrieved from the remote server, not any of the content.

<%
    ' deliberate typo:
    url = "http://www.espn.co/main.html"

    set xmlhttp = CreateObject("MSXML2.ServerXMLHTTP")
    on error resume next
    xmlhttp.open "HEAD", url, false
    xmlhttp.send ""
    status = xmlhttp.status
    if err.number <> 0 or status <> 200 then
        if status = 404 then
            Response.Write "Page does not exist (404)."
        elseif status >= 401 and status < 402 then
            Response.Write "Access denied (401)."
        elseif status >= 500 and status <= 600 then
            Response.Write "500 Internal Server Error on remote site."
        else
            Response.write "Server is down or does not exist."
        end if
    else
        Response.Write "Server is up and URL is available."
    end if
    set xmlhttp = nothing
%>

You might want to parse the results, instead of sending them straight to the client:

<%
    url = "http://www.espn.com/main.html"
    set xmlhttp = CreateObject("MSXML2.ServerXMLHTTP")
    on error resume next
    xmlhttp.open "GET", url, false
    xmlhttp.send ""
    if err.number <> 0 then
        response.write "Url not found"
    else
        if instr(xmlhttp.responseText,"Stanley Cup")>0 then
            response.write "There's a story about the playoffs."
            response.write "Go there?"
        else
            response.write "There is no story about the playoffs."
        end if
    end if
    set xmlhttp = nothing
%>

You may be interested in performing an asynchronous request, e.g. hitting an ASP page that acts like a batch file that gets fired but does not need to return any results. You can simply change the third parameter of the open call to TRUE (and leave out the reference to the responseText value):

<%
    url = "http://www.espn.com/main.html"
    set xmlhttp = CreateObject("MSXML2.ServerXMLHTTP")
    xmlhttp.open "GET", url, true
    xmlhttp.send ""
    set xmlhttp = nothing
%>

Finally, you may want to spoof your user agent, since the MSXML object sends something like "Mozilla/4.0 (compatible; Win32; WinHttp.WinHttpRequest.5)" -- many sites will view this as a spider or 'screen scraper', and for various reasons, might present alternate content -- here are two samples:

<%
    url = "http://www.espn.com/main.html"


    ' this sample posts as the actual browser being used:


    br = Request.ServerVariables("HTTP_USER_AGENT")
    set xmlhttp = CreateObject("MSXML2.ServerXMLHTTP")
    on error resume next
    xmlhttp.open "GET", url, false
    xmlhttp.setRequestHeader "User-Agent",br
    xmlhttp.send ""
    if err.number <> 0 then
        response.write "Url not found"
    else
        response.write xmlhttp.responseText
    end if
    set xmlhttp = nothing



    ' this sample posts as "My funky browser."


    set xmlhttp = CreateObject("MSXML2.ServerXMLHTTP")
    on error resume next
    xmlhttp.open "GET", url, false
    xmlhttp.setRequestHeader "User-Agent","My funky browser."
    xmlhttp.send ""
    if err.number <> 0 then
        response.write "Url not found"
    else
        response.write xmlhttp.responseText
    end if
    set xmlhttp = nothing
%>



If you encounter errors... you can use ParseError to determine the problem.

<%
    set xmlhttp = CreateObject("MSXML2.ServerXMLHTTP")
    ' ... stuff ...
    on error resume next
    xmlhttp.send ""
    if err.number <> 0 then
        response.write "Error: " & xmlhttp.parseError.URL & _
            "
" & xmlhttp.parseError.Reason
        response.end
    end if
    ' ... stuff ...
%>

A common error you might receive:

msxml3.dll error '80072efd'
A connection with the server could not be established

Make sure that the URL is actually reachable. You may have spelled the domain name wrong, or the site may actually be down.

Test using a browser from that machine, or simply running a tracert / ping. Note that ping won't always return results, because many sites block all such traffic (mainly to help eliminate DOS attacks). However, ping should at least let you know the IP address, which means that the domain name was resolved correctly through DNS. Otherwise, it might be that your DNS server is preventing connection.
(http://classicasp.aspfaq.com/general/how-do-i-read-the-contents-of-a-remote-web-page.html)

Can I create an array's size dynamically?


VBScript's arrays have quite a few limitations. You may have noticed if you try this:

<%
    x = 15
    Dim demoArray(x)
%>

You get this error:

Microsoft VBScript compilation (0x800A0402)
Expected integer constant

To work around this, you need to declare the array without a size (or with a constant size, e.g. 0), and then re-dimension it from the variable. Here are two examples; one using a simple array, the other a multi-dimensional array:

<%
    x = 15
    Dim demoArray()
    ReDim demoArray(x)
%>

<%
    x = 15
    y = 10
    Dim demoArray()
    ReDim demoArray(x,y)
%>

Note that if you want to increase the size of an array within a loop, and want to preserve the existing values assigned to the array, you need to use the Preserve keyword (otherwise, the array gets erased and re-created, thus destroying all your values):

<%
    Dim demoArray()
    for i = 1 to 5
        ReDim Preserve demoArray(i)
        DemoArray(i) = "test" & i
    next
%>
(http://classicasp.aspfaq.com/general/can-i-create-an-array-s-size-dynamically.html)