ASPTwitter for legacy classic ASP websites: updated to Twitter API 1.1

Introducing ASPTwitter -- the simplest possible way to implement Twitter within a classic ASP website.

You can download the ASPTwitter source code from my SkyDrive along with a working demo which authenticates and get tweets using the Twitter API 1.1 and the Application-Only authentication model which does not require user interaction.

This classic ASP code library supports Twitter API 1.1 and OAuth. It's easy to extend, and if you do add any new methods send me the updated ASPTwitter.asp file and I'll update the ZIP file on SkyDrive accordingly. I'll add this to source control, probably Git or Codeplex, if I have a chance. main Every code block can easily be ported to other scripts e.g. PHP, Ruby, Python, etc, with minor tweaks.

*** Related: try my simple .NET/C# client for Twitter API. This includes a working demo of a Twitter API proxy API, allowing Twitter API 1.1+ to be used easily in JavaScript code -- without needing oAuth on the client side. ***

 

Background

I've noticed a huge number of people seeking a classic ASP client for Twitter that still works today. I recently updated my own library, ASPTwitter , to support Twitter API 1.1, so I want to sharing my updated code so people don't have to "reinvent the wheel". ASPTwitter boils down to a single class providing simple and convenient methods for authenticating and using the Twitter API.  It's designed to be the simplest possible wrapper around the HTTP response/request calls involved, via the standard built-in XmlHttpRequest component. My working sample code is self-explanatory and also includes some other useful libraries, including code for JSON serialisation/deserialisation for VBScript/JScript.

Last week, as scheduled, Twitter shut down version 1.0 of their API. Thus, anything that uses the Twitter API now needs to use Twitter API version 1.1, which involves some important changes. Many legacy applications therefore broke last week and will need updating. This is obviously a widespread issue; indeed, Twitter's dev website currently displays a notice at the top of the page saying: "June 11, 2013 Having trouble with your app? API v1 is retired and no longer functional. | Read more".

Millions of websites still use classic ASP. It's a stable, well established and convenient legacy technology. In an ideal world you'd convert all of your legacy web apps to ASP.NET MVC, but in the meantime ASPTwitter will fix the problem. I still see new comments online by devs who are implementing new features in their legacy classic ASP web applications and are seeking help with the Twitter API. Devs may also wish to consider Embedded Tweets as a client-side solution for putting Twitter content on your website.

 

Classic ASP loves JSON

Microsoft's server side implement of JavaScript (JScript) in classic ASP, being a server-side scripting platform, was the first platform capable of handling JSON really nicely -- long before anybody was using JSON. Classic ASP allowed two different programming languages to co-exist and work together -- even within same script file! VBScript proved to be by far the most popular language for classic ASP developers, but classes and functions written in JScript were always the nicest way of doing certain things -- including JSON. My ASPTwitter code sample uses "AXE JSON Parser" -- a classic ASP class written in JScript.

The language flexibility we enjoyed in classic ASP lives on in the .NET Framework, Microsoft's major current platform for developers. The .NET CLR currently supports not only the most popular of Microsoft's languages such as C#, but also implementations of Ruby, Python, etc -- you can even mix and match within the same project / library. And .NET provides excellent libraries for handling JSON, available both server-side and client-side, while there are also many superb third-party libraries available. MS has given its approving nod to the continued importance of JS on the server side. Windows 8 applications can be written in pure JavaScript, HTML5 and CSS3. MS staff often citing Node.js being a useful independent example. Microsoft has warmly welcomed a third-party open-source open source JavaScript implementation for .NET. You can even use the V8 JavaScript engine directly in your .NET code -- as used to run JS in Google's Chrome browser. I therefore predict that JavaScript will inevitably become an official language of the .NET CLR. It's clear that JavaScript will continue to be an important language, and not only for the web...

 

Microsoft invented Ajax -- credit where it's due to IE6

Today, Ajax is a fundamental part of the web, and JSON has become a more popular data format than XML for Ajax. Microsoft created Ajax, long before it caught on. The earliest Ajax methodology used the HTML 4 IFrame element first released with IE3+ in 1996 and IE4 in 1997. (Iframe also paved the way for COMET and for several years was the only COMET methodology available to developers.) In 1998/9 Microsoft released the first versions of their XMLHTTP component, first available in IE4 and IE5. When IE6 was released, XMLHTTP was already well established and Ajax was catching on like wildfire. Client-side specifications have evolved, and thankfully standardised accross platforms to a greater extent, yet there are still serious cross-browser problems and true harmonisation seems an unlikely utopia.

It's trendy to overlook the fact that IE6 was ahead of its time, driving major advances in HTML, JavaScript and CSS capabilities -- which literally paved the way for modern client side web applications now taken for granted by both developers and users. Only years later, when the web had evolved in a process catalysed by IE6, did this legacy browser become a problem. As the web moved on from IE6, but users did not, the issue was over-exploited for politicsl purposes in cheap shots by Microsoft's rivals and critics -- above all fuelled by prolific populist anti-Microsoft propaganda from Google and Apple. Nevertheless -- credit where it's due. It's now time for us all to move on from the past and work together to build the web of the future.

16 June 2013

Share the love:

Comments: 115

Add Comment


Hi Tim,

thanks for the code, my only problem is i am only getting retweeted_status tweets and not the standard tweets that my account has posted. is there something i should change "text" to?
again thanks there doesnt seem to be any support for classic asp for v1.1!

Tim Acheson (19 Jun 13, 14:35)

Hi Chris, send me your code, I'll take a look. Tweets and retweets do have a different structure, so you need to handle that. The code in my example should take care of that, though, with the IsRetweet(oTweet) function. I'll send you an email.

Update: thanks for the email, glad to hear you got ASPTwitter implemented and working in your own application.


Hi Tim,

cool, I now use your script on our site (www.elliecomputing.com)

Best,
Armel


A step on would be to cache the tweets so that if too many requests are made the service doesn't go down. again i have the code in php but not in classic asp. Lifes never easy is it! :)

Tim Acheson (21 Jun 13, 17:10)

@Chris Yes, you must cache both the auth token (for 15 mins max) and also the tweets (for at least a few seconds). As noted in my comments in the code. That's essential for acceptable performance of your web app, as well as to avoid hitting API rate limits, and also for resilience -- to handle API down-time etc.

I use my own cache control class which is merely a wrapper around the Application collection -- fundamentally:

Application.Contents.Item("HomeTweetsHTML") = sHomeTweetsHTML

Application.Contents.Item("HomeTweetsHTMLUpdated") = Now()


Hi Tim,

How can we display the twitter dates and time?

Thanks.


Date and Time of the tweet can be outputted via
Response.write(oTweet.created_at)


code runs fine when you call the timeline: sURL = API_BASE_URL + "/1.1/statuses/user_timeline.json" & "?screen_name="

but throws an error if you change from timeline to a search: sURL = API_BASE_URL + "/1.1/search/tweets.json" & "?q="

can uncomment the response write and see that results are being returned, but still get this eoor message:

Microsoft VBScript runtime error '800a01b6'

Object doesn't support this property or method: 'objTweets.length'

/maxi/_twitter/tweets.asp, line 48

any ideas what the cause might be?


Hi thanks for this! just brought back a bunch of sites twitter feeds for me! Was able to update your script to turn the https and @mentions into links and added the time stamps as well.

Can you point me in the right direction to extend this code to allow my users to authenticate using twitter?

Tim Acheson (05 Jul 13, 11:21)

@Phil yes, my demo is just for the Application Only authentication model. What you need is the Application-user auth model, which creates a user context required by many API endpoints. You need to obtain an auth token for the user which just means writing an additional page to handle the callback.

Tim Acheson (05 Jul 13, 11:49)

@Larry results are being returned, so my ASPTwitter class has done its job. ;)

UPDATE: My latest working demo code includes search, in case you still need that (12 July)

The JSON returned by search has a different structure. Try this in your own code, it will work:

<%= objTweets.statuses.length %>

ASPTwitter will get you the data from the API in a nice usable structured object. It's up to you to write your own code display it in the way you want to -- usually just a loop through the tweets. The demo code I include with ASPTwitter demonstrates user timeline as am example. You'll need to look at the JSON, or the API documentation, for the other API endpoints. The JSON may also contain a useful error message. Unlike user timeline, the JSON returned by search nests tweets within an extra "statuses" collection, that's all.

There's a link to a good JSON editor/explorer n my comment directly above the response.write you uncommented. This makes it easy to see what's happening and update your own code (or my demo) to use the JSON returned by the API.

David Peach (09 Jul 13, 15:33)

A great plugin. Literally took about 5 mins to implement into a site. Super fast. Thanks a lot for it.

Rens van Stralen (10 Jul 13, 14:41)

Hi Tim,

Great script! Easy enough for me to implement also :-)

Is it possible to extend it to a dynamic Twitter timeline search?

Thanks

Adem Colak (11 Jul 13, 02:44)

Hi Tim,

Where is the donation button :)

You saved my day!

Thank you so much..

Tim Acheson (11 Jul 13, 16:27)

@Rens Yes, for search just change the URL:

https://dev.twitter.com/docs/api/1.1/get/search/tweets

For quick results, just pass through the while Request.QueryString collection object rather than play with individual parameters.

Also note the slightly different structure of the response for search.

I'm updating the demo to work with search right now.

Rens van Stralen (12 Jul 13, 10:51)

@Tim Thanks for your reply! I'll give it a try :-)

Tim Acheson (12 Jul 13, 17:58)

@rens I've updated the demo to include search, and posting a tweet too.


Tim-

Great code...however I do have challenge.

I would like to update your code so that I would have the ability to send STATUS UPDATES (Tweet) with it. My application in Twitter (dev.twitter.com) is already setup with Read/Write access, but the nature of the often ambiguous nature of Twitter is that this is not easily accomplished.

So, in essence, I would like to be able to use your code so that when I hit this page, a Status Update could be sent, assuming that I already know that proper oAuth keys, etc.

It is great code and will definitely be extremely helpful in my next project. Thanks for taking the time to build this (and post it so that others can benefit from your great work).

C.J.

Tim Acheson (12 Jul 13, 21:14)

@CJ Download the latest version of my ZIP file using the link above. I've now updated it with a post tweet example that will work as soon as you run it with the correct oAuth data. I added code comments for solving all the most common issues. Thanks for the emails you sent me today -- pleased you mentioned E3! And thanks for supporting my projects, much appreciated.

Rens van Stralen (14 Jul 13, 15:21)

Nice scripting!


First off, THANK YOU. This is super useful. I'm currently trying to make a proxy asp page for my organization's twitter feed. The most useful format would be for it to output as json. I saw in one of your oauth examples there was a page that outputs json, but I don't believe it includes any caching and it says not to use for production. This tweets.asp example seems to work great except that I'm noticing some characters come back garbled. In the json example the character \u2019 shows up, it's a curly quote, but it gets garbled when getting encoded in this tweets.asp example. To get straight json output that would be cached, what would be my best option? I've coded in PHP a decent amount, but never ASP, so while I can read the code, writing it is a much slower process. :) Thanks again for all of your work on this.

Tim Acheson (18 Jul 13, 12:26)

@Neil Glad to hear you're finding it useful. My ASPTwitter class does return the raw JSON, and it sounds like that's what you need. The purpose of the class is to be the simplest possible Twitter API proxy. Let your own application handle the caching. You could just add one line of code to store the raw JSON response in the Application.Contents collection. There are many examples of caching classes. Personally, I cache the final HTML for 1 minute and the bearer token for 15 mins -- 1 line of code to cache the HTML.

Simple classic ASP caching example:

Public Function GetCachedTweetsHTML

 Dim sHTML
 
 If IsCacheExpired Then
  %><!-- Tweets.asp: Cache expired. -->
  <%
  sHTML = ""
 Else
  sHTML = CStr("" & Application.Contents.Item(HOME_TWEETS_CACHE_KEY))
 End If
 
 If sHTML = "" Then
  
  sHTML = GetTweetsHTML
  
  ' If no Tweets, do not update cache
  If Len(sHTML) > 150 Then
   With Application
    .Lock()
    .Contents.Item(HOME_TWEETS_CACHE_KEY) = sHTML
    .Contents.Item(HOME_TWEETS_UPDATED_CACHE_KEY) = Now()
    .Unlock()
   End With
   %><!-- Tweets.asp: Tweets loaded from API. -->
   <%
  
  End If

 Else
  %><!-- Tweets.asp: Tweets loaded from cache:
  <%= Application.Contents.Item(HOME_TWEETS_UPDATED_CACHE_KEY) %> -->
  <%
 End If

 GetCachedTweetsHTML = sHTML

End Function

Private Function IsCacheExpired
 const CACHE_DURATION_SEC = 7200 ' 7200 = 60 * 60 * 2 = 2 hours

 If IsDate(Application.Contents.Item(HOME_TWEETS_UPDATED_CACHE_KEY)) Then
  Dim dUpdated : dUpdated = CDate(Application.Contents.Item(HOME_TWEETS_UPDATED_CACHE_KEY))
  If DateAdd("s", CACHE_DURATION_SEC, dUpdated) > Now() Then
   IsCacheExpired = False
   Exit Function
  End If
 End If

 IsCacheExpired = True

End Function
Scott DeSapio (20 Jul 13, 17:28)

I just recently updated my Classic ASP VBScript OAuth library to use 1.1. You can download an updated version of the code here: http://scottdesapio.com/VBScriptOAuth/

Scott DeSapio (20 Jul 13, 17:38)

Hey Tim,

I just downloaded ASPTwitter. Great work. I also noticed you've incorporated my VBScriptOAuth Lib (I always love to see that). Have you forked it on Github? Do you have any updates you'd like to push?

Sorry I didn't catch your comments on my OAuth page. If I miss you again, you can reach me anytime at scott[@]desap.io or tweet me @sdesapio.

Thanks,
Scott

Tim Acheson (22 Jul 13, 09:49)

@scott Thanks -- the update to your legendary library, the de facto standard library, is what everyone has been waiting for of course. I only used the util methods of it in my simple demo. My library is just a workaround to fill the gap until yours was fixed to work with Twitter API 1.1.


Hi.

First thanks for the script, helped me a lot.

I have a question. The date looks like this:

Fri Jun 21 13:28:36 +0000 2013

How do I translate the date in my language?

I would also like adata was only day month and year.

Can you help me? Thank you.

Tim Acheson (24 Jul 13, 17:29)

@Eric glad you found it useful. In my working demo the date is not displayed, but I think it's returned as a proper VBScript date object. If so, you can use the standard date time functions like Day(), Month(), FormatDateTime(), etc. Either way, if you do need to parse date values like the example you gave from text, there are various ways to do it, e.g. CDate(), etc. You could even use JScript if for a more JSON/JavaScript friendly environment. You may need to consider localisation, e.g. with an LCID attribute in the declaration at the top of your script. Scott's utils, included in my demo, have some useful functions for handling dates, too.


Hi having problems implementing this, changed the 4 constants but just getting

msxml3.dll error '80072ee2'

The operation timed out

Tim Acheson (26 Jul 13, 11:36)

@Paul it sounds like the web app is unable to access the Twitter API. Try running it on a different machine. Can you describe how the website is hosted? Are you running it on your local PC? Last time I saw an error like that it was on an in-house server which had no internet access hence no access to external APIs. I fixed it by entering the correct proxy address for that network in the internet settings on that server or PC. A firewall could block API access, too, but that's unusual.

Johan van Soest (31 Jul 13, 21:48)

Dear Tim,
Thanks for your free source code for accessing the new Twitter 1.1+ API.
It was indeed easy to configure on my site http://www.vanSoest.it.
Kind regards,
Johan


Hello all-

Just a quick comment. I am the first to "grab" code and throw it into a production environment....which works well. However, if you have benefited from this code, please send a little "financial compensation" to Tim. I have done this a couple of times now and we all benefit from Tim's great ASP code.

Additionally, if you want something in this Classic ASP Twitter code to work better (or faster), such as Status Update with Media....then send him some financial love....so that this can get done.

It is a simple way to give Tim the motivation to maintain this code. Based on the sheer number of comments, I can see that I am not the only benefiting from his code.

Paypal (UK) is one way to go.

Looking forward to more updates.

C.J.

Tim Acheson (16 Aug 13, 08:39)

@C.J. Thanks dude! lol :)


Hi Tim.

First, thank you very much for putting your code out there. I think it will really save me a ton of time.

I have a question regarding your ASP twitter library. Throughout the code you have the User-Agent set as "timacheson.com." Should that be changed to the site on which my app sets?

Thanks in advanced for your response.

Terrill


Tim,

I have another issue I'm hoping you can help me with. I have tried to modify the code in order to read mentions (/1.1/statuses/mentions_timeline.json).

I tried to modify the GetUserTimelineJSON function but it did not properly authenticate. After checking with dev.twitter.com I saw that the function requires Application-user authentication. So I tried to add that to the function similar to the way you do it for the post tweet function but, although a bit of a different error, still unable to authenticate. The current error I'm receiving is [Could not authenticate you","code":32].

Any help would be greatly appreciated.



when I install this to my IIS environment I get "Include file not found" errors, I've verified the files exists in place, I have 'parent paths' enabled in IIS and as a last resort I changed all the '#include virtual=' instances to '#include file=' but still get an error at line 213 of ASPTwitter.asp where it looks for the include file '/Libs/VBScriptOAuth/oauth/_inc/hex_sha1_base64.asp'.

What do I need to change to get it to work?

Tim Acheson (05 Sep 13, 12:20)

@Terrill The user agent is up to you, but I'd be suggest being consistent.

The code can be extended to do mentions, it can be tricky working with the API but it can be done with minimal additions to the existing code.

Tim Acheson (05 Sep 13, 12:21)

@Tamak it sounds like you're doing everything right. Ensure that the user account under which IIS is running has read and execute access to the files.


@Tim - thanks. I've confirmed the permissions on my local IIS box (where I run / test other web apps / sites done in various languages and frameworks.

I also just tried moving all the files out to a LIVE IIS web server where I have a few live websites running (IIS 6)... still ultimately end up back at the same issue / error: "The include file 'Libs/VBScriptOAuth/oauth/_inc/hex_sha1_base64.asp' was not found. error '8000d001'" -- I cant figure out what Im missing. could it be related to the fact that in twitter, my aps has an access level of 'Read-only' under 'OAuth settings'... or could it be related to @ Anywhere domains under the apps settings?

Just cant figure out what Im missing here.


Hi Tim, thanks a lot, good Job!
.. Script originally configured for root directory, but i will put the script in sub-dir.
It gives error for not-found for includes. what files should I change?


Thanks Tim for this wonderful script.
Much respect for the hours of work that you put in.
You can watch it on my site www.sdcdarts.nl


Dear Tim,
Thank you for the code,
I found a problem with the demo (Tweet.asp)while trying to send a message with non alphanumeric characters like "Test to be deleted #mytest". I'm getting the error: [{"message":"Could not authenticate you","code":32}]
No problems with the same message without the "#" character "Test to be deleted mytest".
Could you provide any hint on how to solve this.
Thanks
Kind regards,
Jolhan


I am trying use this for Tumblr Api, but I get a error: {"meta":{"status":401,"msg":"Not Authorized"},"response":[]}


my code:

Authenticate ()
GetLocalAllTumblr()
LogOutTumblr()


Function Authenticate ()
Dim objOAuth : Set objOAuth = New cLibOAuth
objOAuth.ConsumerKey = OAUTH_EXAMPLE_CONSUMER_KEY
objOAuth.ConsumerSecret = OAUTH_EXAMPLE_CONSUMER_SECRET
objOAuth.EndPoint = TWITTER_OAUTH_URL_REQUEST_TOKEN
objOAuth.Host = TWITTER_API_HOST
objOAuth.RequestMethod = OAUTH_REQUEST_METHOD_GET
objOAuth.TimeoutURL = OAUTH_EXAMPLE_TIMEOUT_URL
objOAuth.UserAgent = TWITTER_APP_NAME

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 2. Add proprietary request parameters.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
'objOAuth.Parameters.Add "oauth_callback", OAUTH_EXAMPLE_CALLBACK_URL

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 3. Make the call.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
objOAuth.Send()

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' 4. Evaluate the response.
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

Session(OAUTH_TOKEN) = objOAuth.Get_ResponseValue(OAUTH_TOKEN)
Session(OAUTH_TOKEN_SECRET) = objOAuth.Get_ResponseValue(OAUTH_TOKEN_SECRET)
Session(TWITTER_SCREEN_NAME) = objOAuth.Get_ResponseValue(TWITTER_SCREEN_NAME)
Set objOAuth = Nothing
End Function


Function GetBlogsInfo ()
Dim objOAuth : Set objOAuth = New cLibOAuth

If objOAuth.LoggedIn Then



'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' setup oAuth object
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
objOAuth.ConsumerKey = OAUTH_EXAMPLE_CONSUMER_KEY
objOAuth.ConsumerSecret = OAUTH_EXAMPLE_CONSUMER_SECRET
objOAuth.EndPoint = "http://api.tumblr.com/v2/user/info" 'TWITTER_OAUTH_URL_UPDATE_STATUS
objOAuth.Host = TWITTER_API_HOST

objOAuth.Parameters.Add "oauth_token", Session(OAUTH_TOKEN)
objOAuth.Parameters.Add "oauth_token_secret", Session(OAUTH_TOKEN_SECRET)
objOAuth.RequestMethod = OAUTH_REQUEST_METHOD_POST
objOAuth.UserAgent = TWITTER_APP_NAME

objOAuth.Send()

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' check the response
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim strResponseText : strResponseText = objOAuth.ResponseText

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' error code
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
Dim strErrorCode : strErrorCode = objOAuth.ErrorCode

'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''
' check for errors
'''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''

If Not IsNull(strErrorCode) Then
Response.Write strErrorCode
Else
Response.ContentType = "text/html"
Response.CharSet = "utf-8"
Response.Write strResponseText
End If

Else
Response.Write "Error"
End If
Set objOAuth = Nothing
End Function



Hi Tim,
just adjust CONSUMER_KEY,SECRET,TOKEN,etc.. and the scripts work very well.
But how tweet also images and text?

Thanks,
RM

Tim Acheson (04 Oct 13, 12:49)

@Jolhan My basic demo needs updating to handle encoding of different characters. It's a starting point. It's open source, so if you do it feel free to share. :)

Tim Acheson (04 Oct 13, 12:49)

@Jerry The Tumblr API works differently to the Twitter API. You'll need to adapt the code accordingly.

Tim Acheson (04 Oct 13, 12:52)

@RM Glad you found it useful. My code is a starting point. You'll need to expand it to cover additional functionality. I have code locally that does lat/long geolocation. If you add media support, feel free to share the code and I'll pass it on here. :)


Is there anyone with help about this? It fails if I even try to post a period. I need to be able to post the occasional link and this code works awesome except for this single issue and I can't find work around anywhere.

Tim Acheson (11 Oct 13, 13:50)

@Kevin hi -- you just need to get the encoding right. And that can differ between the post data and the OAuth. You may need to double encode (URL Encode then URL Encode the result). I and others have got it working with periods and other characters.

Use the official OAuth Tool on the bottom of the right column on the API page for the update endpoint, to see what the correct request must look like.


Really nice work, thanks!

Has anyone gotten this to work with special characters? I can't get it to post a simple url or special chars like "+" and "%" - no matter if i urlencode or double urlencode it. Just gets the same "Could not authenticate you" message as mentioned by others. If anyone has any ideas, it would be much appreciated!


Hi there,

I've tried all sorts of different ways of encoding and not encoding and the only way I can get it to post a status with full stops (periods) in it is to double URLEncode it but that makes it garbage. Has anyone worked this out yet..?


SOLUTION TO SPECIAL CHARACTERS.

Hi all, worked through this today and sorted out the issue with special characters. Use this solution if you are getting the ever so useful 'cannot authenticate' error when trying to update a status.

I used the OAuth tool on the twitter developer site to compare what the base string should be to what this script was producing.

The querystring parameter is created using a simple server.urlencode which is fine and dandy.

The base string is created in the GetOAuthHeader function.

In the GetOAuthHeader your status string (the tweet) is first being encoded using the HeaderEncodeValue function. This replaces all spaces with %20.

This string is then server.UrlEncoded and slotted into the base string.

If you consider the following string;

Maybe he'll find. //

according to the OAuth tool it should be encoded as;

Maybe%2520he%2527ll%2520find.%2520%252F%252F

but this script ends up with

Maybe%2520he%27ll%2520find%2E%2520%2F%2F

Couple of things wrong with this;
1 - only the spaces have the double encoded % (%20 becomes %2520) the other special characters dont.
2 - the period/dot/fullstop character as been encoded but twitter expects this as a .

To fix this first cut and paste the snippet from;

http://forrst.com/posts/OAuth_Encoding_Function_in_ASP_VBScript-7ht

Stick this function somewhere accessible. This will encode all special OAuth characters for you.

Alter this function;
Private Function GetOAuthHeader(ByVal sURL, ByVal sStatus)

in the ASPTwitter.asp file.

Change this line;
sStatus = HeaderEncodeValue(sStatus)
to;
sStatus = oauth_encode(sStatus)
sStatus = replace(sStatus, "%" , "%25")

which encodes all characters and then re-encodes all the % to %25.

Then change;
baseString = Replace(baseString, "{6}", Server.URLEncode(sStatus))
to
baseString = Replace(baseString, "{6}", sStatus)

Fingers crossed it should work for you. Ive not tested it alot I just wanted to get special characters working so use at your own risk.

Thanks to Tim for putting all this together, I was already used the same OAuth library this class uses so it was a simple drop in for me once this encoding issue was solved.


Tim,

got it to work finally after coming back a few weeks later with a fresh set of eyes! For any who might have same issue (my problem was the virtual includes not working) I simply had to use the full path to the included files...

Is there a way for me to get the raw JSON output instead of the LI's output on your defaut "tweets.asp" page? where / how can I access the raw JSON data? I'd like to use it as a source for some jquery parsing and testing.

Thanks for a great solution to the issues brought about by the new twitter api!


Answered my own question on how to get to the raw JSON:

basically just look at /Libs/ASPTwitter/ASPTwitter.asp and on line 186 you'll see a commented out line where theres a textarea that holds the json code!


Tim,

Hi! I'm trying to incorporate designchemical's social stream plugin, but it uses a php doc to authenticate. I'm in VS, and it doesn't run php by default. Any idea how I would set this up in this environment? Thank you!!


Hi, I'm in the same boat as Mike, trying to get jQuery Social Stream from designchemical to work. Looking through their code there's the option to add an URL to the twitter settings. It's designed for their php file but I was hoping to use aspTwitter instead.
I've got the default.asp page to display some tweets so I know that the keys are working.
I think the php file returns the tweets as JSON. What do I need to get the same from ASPTwitter?
Sorry if it's really obvious; my background is more LAMP, so as you can imagine, I'll really missing the php right now!
Thanks for all your work on this, it's very much appreciated
Tim


@Tim Smith -- not sure if this is what you're after but I needed to get raw JSON back from asptwitter as well and as my earlier post says I found where it was used in his example and I just customized the code to do two things: 1) render a raw live json feed of results and 2) also create a flat / local .js file to hold a cached copy of the json -- as a fall back in case the ajax call fails for some reason ( I noticed a random / intermittent error 215 code coming back from twitter -- rarely, but still wanted to not have the user get that error ).


basically just look at /Libs/ASPTwitter/ASPTwitter.asp and on line 186 you'll see a commented out line where theres a textarea that holds the json code!


Rolf-

I have confirmed that your solution does in fact solve the Status Update issue that has been plaguing me. Excellent work and diagnosis.

C.J.

Tim Acheson (02 Dec 13, 19:08)

Rolf, CJ, awesome work! The power of crowd sourced solutions is amazing. I put this out there hoping that some of those who used it would take it to the next level, and that has certainly happened., I'll post updated code in a Zip file soon with credits of course.


Tim, was there a change to the twitter API or something that would cause your solution to no longer work? I had an awesome series of test uses of it up and running on my production server where I was just experimenting and its been about a week since I last used any of it, now I noticce none of its working... I've checked my API keys / credentials and verified they are all valid / correct but still nothing... anyone else having issues as a last resort I guess I'll setup a new app in twitter and get new credentials and try again.

Mike Brind (23 Jan 14, 10:14)

Tim: Excellent work on the library

Rolf: Your contribution is invaluable.

Thank you so much both of you.


awesome project yeu have here. thanks for sharing it. QUESTION: I have set it up locally and have it working to retrieve status updates and to post status update from my twitter account but need to know if its possible to use this to allow a user (currently logged in to twitter on their mobile device) to post a status update to THEIR timeline. is that even possible or do I need to do some sort of 'sign in to twitter' process within my app that authenticates that user?


Hi!
I'm quite a newbie at this, how do I use this?

thanks anyway


This looks great. I'm curious if you would be able to point me in the right direction to enable this to work with this jquery plugin (http://codecanyon.net/item/jquery-social-stream/2103997?WT.ac=solid_search_item&WT.seg;_1=solid_search_item&WT.z;_author=designchemical)

Thanks in advance!


Hi, Tim!
Thank you very much for sharing this wonderful library.
I have a question. How can I handle array data like entities from twitter object? For example, I want to get expanded_url. I tried

eurl = oTweet.entities.urls[0].expanded_url

But it doesn't work.Of course I don't think the above is the right way of using array data since the expanded_url can be in 2nd or 3rd item or urls entity.

Could you help me?

Regards,
Jay


Oh, I have one more.

When I retrieve tweet id, for example
tw_id = oTweet.id

I got scientific number.

4.41000420413309E+17

I need real number for this.

(for the above question, I could get it using

eurl = oTweet.entities.urls.[0].expanded_url

but still want to know the solution when expanded_url is not in [0])

Thank you very much in advance.

Jay


Many thanks
This worked very well for me on a Classic ASP site where I was asked to implement the client's timeline.
The clear and commented sample code is a great help.


I got both TWITTER_API_CONSUMER_KEY and TWITTER_API_CONSUMER_SECRET. Where can I find or get TWITTER_API_OAUTH_TOKEN and TWITTER_API_OAUTH_TOKEN_SECRET from Twitter? Is there instruction I can read?


Trying to put this together -- made an object which gets its data from the local _Tweets.asp page and end up getting this

Microsoft VBScript compilation error '800a0401'

Expected end of statement

/_Tweets.asp, line 187

HasKey = CStr("" & oTweet.get(sKeyName)) Not = ""
-----------------------------------------^

The only thing I changed was one of the
o ID="tweets"> since it was referenced twice I changed the second one to ID="tweets2" since it was just an O list didn't think that would mess anthing up.

To be clear _Tweets.asp should be the "working demo" right? it was the only one with the API in there -- I can get my own API but wanted to at least try it once so I can work on my formatting.

Tim Acheson (09 Jun 14, 15:08)

@Josh Tweets is a working demo. It works, as soon as you put your own correct Twitter API keys into the config. The error message that you are getting does not occur in the working demo, and it looks like it's just a syntax error in your modified version of the code.


I'm trying to use your code for updating my status through an asp page Everything works ok if status is in English characters but when I want to post something using Greek characters it fails with following error

"errors":[{"message":"Could not authenticate you","code":32}]}

any idea?

Tim Acheson (26 Jun 14, 16:13)

@Ralf TWITTER_API_OAUTH_TOKEN etc come from your own Twitter dev account. Full details in the comments above these lines of code! If you don't specify those, the demo outputs a message explaining how to get them.

Tim Acheson (26 Jun 14, 16:13)

Hi Nick, see Rolf's solution for special characters in his comment above.


Thanks for the reply.

I followed Rolf's recommendation (correct link http://zurb.com/forrst/posts/OAuth_Encoding_Function_in_ASP_VBScript-7ht). Although it worked with special characters it didn't work with Greek characters.

I did manage to make it work though.

Here is what I did to make it work

After you follow Rolf's solution
find sStatus = oauth_encode(sStatus)
change sStatus = oauth_encode(Server.URLEncode(sStatus)) 'encode Greek characters
comment sStatus = replace(sStatus, "%" , "%25") 'we will do it later on

At Rolf's function oauth_encode
find oauth_encode = replace(str,"%","%25")
change oauth_encode = replace(str,"%2E",".") 'twitter wants .
oauth_encode = replace(oauth_encode,"%","%25")


hope it helps!

kankasmart (30 Jun 14, 11:09)

So, how can i tweet turkish chracters ? i tried to add some chracters to oauth_encode function, but i continued to get error : Could not authenticate you","code":32

can you help me for turkish chracters ?


So i'm trying your code , I added by tokens/keys etc..

Try the test tweet from tweet.asp and get this;

"{"errors":[{"message":"Could not authenticate you","code":32}]}"


So is this code out of date now or what?
Because I run the "tweets.asp" file and get error 500... changed the keys and username etc properly...


Using your ASP pages how can I put a twitter for somebody?? because when I tried and I send a comment using the @userX + text, I got an error saying
{"errors":[{"message":"Could not authenticate you","code":32}]}
Can you please help me


I also have an error trying to get mentions:

"Your credentials do not allow access to this resource","code":220}


Phil,

Did you solve the user authentication issue??
Did you have the mentions or update @UserX implemented??


Hi Tim, using you code raw isn't ideal. What I want is a page or a function I can call from classic ASP code passing a tweet and it posts it on my behalf.

I've amended the code to create a sub which does this (as long as I include ASPTwitter.asp in the calling page), but it seems very variable... sometimes it works and sometimes it fails (usually with Object doesn't support this property or method: 'objTweets.id_str').

Have you any idea what is causing this behaviour, I'd have expected it to either work all the time or fail all the time?


I should add that it seems to always fail if I use anything except letters/numbers (although that's not exclusively when it fails!)

Tim Acheson (30 Jul 14, 12:13)

@Steve see comments above, code has been posted to solve that.

Tim Acheson (30 Jul 14, 12:17)

@DrewDub, @Daniel check your API settings on https://dev.twitter.com. Make sure you're using the correct auth tokens, and make sure you've enabled write access -- it's read only by default. As per the comments in the code.

Others are using it successfully, so probably something subtle missing at your end.


Hi Tim, I'm sure what you say is correct, but there are a lot of "above" comments and I cant work out how to get this working. Looks like I'll have to give up.

Don't suppose anyone has a basic "send_tweet" routine I can use do they?


Hi, I've almost got this working combining the original code with the encoding fix applied... it still wont include a £ sign without falling over though... any ideas?


This £ sign thing is really irritating

I've added: oauth_encode = replace(oauth_encode,"£","%A3"), to the encoding function and can see that just tweeting a £ my basestring looks like this (just the end bit)

oauth_version%3D1.0%26status%3D%25A3

If I use the oauth tool and simply put a £ sign in is generates a signature base string which looks like this

oauth_version%3D1.0%26%25C2%25A3%3D
the difference being the "status%3D" text which is assume must be optional and %25C2 shows in the oauth tool version which translates to  (hope that shows up!)

I actually tried just setting the status to be as per the oauth tool output but am still getting the failures... there must be a solution to this!

Help


Thanks Rolf,
The function mentioned on the link is:

http://zurb.com/forrst/posts/OAuth_Encoding_Function_in_ASP_VBScript-7ht

function oauth_encode(str)
oauth_encode = replace(str,"%","%25")
oauth_encode = replace(oauth_encode,"!","%21")
oauth_encode = replace(oauth_encode,"*","%2A")
oauth_encode = replace(oauth_encode,"'","%27")
oauth_encode = replace(oauth_encode,"(","%28")
oauth_encode = replace(oauth_encode,")","%29")
oauth_encode = replace(oauth_encode,";","%3B")
oauth_encode = replace(oauth_encode,":","%3A")
oauth_encode = replace(oauth_encode,"@","%40")
oauth_encode = replace(oauth_encode,"&","%26")
oauth_encode = replace(oauth_encode,"=","%3D")
oauth_encode = replace(oauth_encode,"+","%2B")
oauth_encode = replace(oauth_encode,"$","%24")
oauth_encode = replace(oauth_encode,",","%2C")
oauth_encode = replace(oauth_encode,"/","%2F")
oauth_encode = replace(oauth_encode,"?","%3F")
oauth_encode = replace(oauth_encode,"#","%23")
oauth_encode = replace(oauth_encode,"[","%5B")
oauth_encode = replace(oauth_encode,"]","%5D")
oauth_encode = replace(oauth_encode," ","%20")
end function

Serge Billiouw (18 Aug 14, 08:43)

Hi Tim,

Quick question : How do I check if a key exists ? Eg. Media exists IF there is a picture in the tweet, the key is not presented in the JSON if there is no picture in the tweet ...

thanks !
Serge

Tim Acheson (26 Aug 14, 16:23)

Thanks for working that out while I was on holiday! :D

If anyone would be willing to send me an updated version of my original Zip file with this fix added (be sure to comment and credit the work appropriately), I'll gladly upload it and update the link accordingly.


Hey Tim,
Great stuff, using it heartily,
Quick question: Recently, last month or so,
Ive been receiving a LOT of timeout errors...

"msxml6.dll error '80072ee2'

The operation timed out"

Ive tried myriad different values for the oXmlHttp.setTimeouts parameters, but doesnt seem to make any difference...

Any idea what causes that?
Is it a twitter api thing?

frustrating part is there doesnt seem to be anyway to not lock up my page with the error...

Thanks again for the kick ass code... any thoughts are appreciated.

Tim Acheson (05 Sep 14, 11:15)

Hi Brian, glad to hear you're making use of my library. Twitter API does time-out sometimes, but it's as likely that it's a network issue at your end or between you and Twitter. Also consider whether you're spamming the API too much. What's your hosting setup?

Whenever I use a third-party API, for resilience and performance it's always worth adding a caching layer. Use a function like my GetCachedTweetsHTML() example above . Your web app will run faster, and when there is a timeout nobody will notice because it can fall back to the last known good value from the cache.


Hey Tim,
Interesting test...

If you have a moment...

Server 2008 r2 -
iCount set to 10 : Runs perfectly every time
iCount set to 20: random timeouts
iCount set to 25 or higher: timeout every other refresh

Server 2003 -
seems to be happy with almost any setting.

--------------------

Have been running into this over and over lately, like over the couple weeks pretty much constantly, been pulling out my hair trying to track down the issue...

So yesterday, i downloaded a fresh copy of your ASPTwitter (awesome work btw)

Placed it on a win 2008 r2 server, added consumer key and consumer secret and off it goes runs great no timeouts...

Changed the iCount variable to 20, and started running into random timeouts just like with my code.

Changed it to 50 and basically replicated the exact behaviour im having with mine where the data will load initially, but if you try to refresh within like a minute or two... times out every time.

Same code on a win 2003 server, executes perfectly every time.

Ive tried every combo and internet solution i can find from setting timeouts :
oXmlHttp.setTimeouts 50000, 60000, 10000, 10000 to setting sessions to false... different versions of MSXML2...



Any thoughts on either whats different between the server versions or possible solutions?

Tim Acheson (12 Sep 14, 10:27)

Hi Brian, interesting observations, thanks. I am very confident that this is an issue with your setup, perhaps the server (even antivirus) or network/proxy. I have re-tested the original code, setting iCount to 20, 50, 100, and manually refreshing the page a few dozen times. It always works. I cannot reproduce the problem, which is a shame because if I could perhaps I could diagnose and fix it!

I've tried it on various machines at home and at work, e.g. Windows Server with IIS7, Windows XP Pro with IIS6, and especially on Windows 7 Enterprise SP1 64bit running IIS 7.5.7600.16385 in an app pool with 32bit applications enabled . Which version of IIS are you running?

It would be worth running a network analysis tool like Wireshark to see exactly what is in the the request and response. It seems unlikely that the API its self is timing out for the larger requests, although it's possible. The main effect of increasing iCount is, of course, to increase the size of the response and the size of the JSON object. Either of those things could potentially cause a problem on the network or within the XMLHTTP COM object or IIS web app. It sounds like you're already playing with some of the right options. Which versions of msxmlhttp have you tried? Try them all! Especially try msxmlhttp 6: Server.CreateObject("MSXML2.ServerXMLHTTP.6.0"). Also try even bigger timeouts like xmlhttp.setTimeouts 999999, 999999, 999999, 999999! See what the maximum is! If that fixes it you could then find out which of them is the issue -- resolve, connect, send, receive -- that's be interesting.

Also try a different client, like ASP.NET, or SoapUI, etc -- to see what happens when you take classic asp xml http on your server out of the equasion, and importantly be sure to get an exact copy of the response that's being received by msxmlhttp when it fails! Then you can create your own web app serving that exact response, use that instead of the Twitter API, and see if your xmlhttp request can handle that instead. You could just use my Twitter API Proxy to intercept and take full control of the response from Twitter or just to analyse it.

Also try playing with the IIS config and the ASP web app/page settings including EnableSessionState="False" at the top of default.asp.

Tim Acheson (12 Sep 14, 10:36)

@Brian Also try handling errors with On Error Resume Next at the top of the script, and additional handling in the xmlhttp code block:

Response.Write xml.ReadyState
If Not xml.ReadyState = 4 Then
      Response.Write "Problem!"
      Response.Flush
End If

In the app pool for the classic asp web app, try changing the number of worker processes. It's probably 1, so try 3. This should not be necessary, but it is an experiment.

And try it on your work/home PC, or even use an Amazon EC2 instance if necessary, just to show yourself that it works in different environments.

Keep me informed!


So how does it work with "sign-in with twitter" ?


hi sir, can u send me the code which display the Followers of my twitter account on my website

Ewan Stevenson (10 Dec 14, 15:51)

Tim,

Thanks for this code. I'm a big classic ASP fan too but recently started to use C# in WebMatrix. I have a Twitter and Facebook app and some Twitter authenticated users (OAuth 2). Its a football prediction game. I'm simply wanting to find the line of code that could send a tweet of their results from the adminpart of the game to a twitter user's account. Is this possible to do if the user was not logged into the app/game at the time the admin page wanted to send the results? Is there a line of code in your vbscript that I could translate into C# JQuery etc. Hope you can point me in the right direction. :) Thanks


hi, I need help to integrate twitter cards in asp.net developed eCommerce website. some easy way that could add meta tags and og titles on product pages for better tweets on our twitter page as Twitter Product Cards.


Hi Tim - great work! I'd love to see a media/upload.json function where we could upload images via the API, then attached the media_id of that upload to a statuses/upload.json tweet (essentially, post a tweet with an image in it). I've been struggling to do this myself - help very much appreciated!


I keep getting the following error :-

{"errors":[{"code":32,"message":"Could not authenticate you."}]}

....when adding a "special" character to a tweet e.g. [ ! * : // .... etc.

I am using the original code.

"Test to be deleted" works fine and posts the tweet.

"Test to be deleted http://www.bbc.co.uk/" produces the above authentication error.

Am I missing something obvious here?


Hi ,
I have a requirement like , we have some of the candidates details with us , so we need to search candidates from twitter and getting she/him 's profile (like people search from Google) can you help me how can do this.

Thanks.


when i use below request using the API1.1...
https://api.twitter.com/1.1/direct_messages.json
https://api.twitter.com/1.1/statuses/mentions_timeline.json
I'm getting Error as
The remote server returned an error: (403) Forbidden...
please help me out...


Excellent... thanks very much, saved my bacon updating an old classic asp site!

Tim Acheson (26 Jan 16, 14:20)

Update: a new version of ASPTwitter, v1.2.0, is now available, updated with some of the crowd-sourced improvements in the comments above. Enjoy!

Download ASPTwitter 1.2.0 here!

Thanks once again to all contributors for taking my quick prototype and making it a bit better, I wouldn't have had time to do this myself.


i'm beginner and i want to know how to get start..... need help


@Tim thank you, this code is very sweet! Can you give me an idea if its possible and how difficult ti could be to upload an image? I have been reading the twitter API's POST media/upload section and can see how they expect to see an image. Can be either base64 or the raw binary data. Thanking you


Set your price - happy to put some finance into the media upload. Can see it requires different OAuth and submission techniques.


Does the new library allow image uploads to Twitter?


Ciao Tim!

your code works great, thank you very much for you time and energy in updating it too!

I have one question only: I'm using this script to display the very last tweet on a couple of websites, but it looks like the code doesn't catch a pinned tweet even if it's the most recent one.
Is there any way to retrieve a pinned tweet? I don't know if this feature is still unavailable via Twitter APIs.

Thanks a lot!


How can I turn the @ sign to links?


I always get error:
{"errors":[{"code":215,"message":"Bad Authentication data."}]}
when trying to view or search. The BearerToken is always empty.

Status update works.

Any ideas what that could be?

Hrishikesh Menon (01 Mar 17, 11:12)

You need to provide the
OauthToken, Oauthsignature, consumerkey, signatureMethod, timestamp, nounce, and oauthversion then you will get the correct details..
please go through
https://dev.twitter.com/rest/tools/console

Johan van Soest (06 Jun 17, 01:06)

Dear Tim,
FYI: I just got Symantec to white-list the file AXEJSONParser.asp (Part of this twitter plugin). Antivirus falsely removed the file from my website https://www.vansoest.it.
Thanks again for this great free library.
Kind regards,
Johan

Jamal alaneb (20 Jun 17, 23:45)

Hi Tim.
I appreciate this work for you and your effort to share with the public.I am from Syria and i try to download The API for tweeter ,but it appears me mot avaliabel So is there something wrong..Thanks alot

Johan van Soest (17 Nov 17, 01:35)

Dear Tim,
After all these years your library is still functioning great.

However Twitter recently has increased the maximum size of a Tweet from 140 to 280 characters. When tweets are longer than 140 characters, the library receives truncated tweets, with the character "…" added and an url to the original tweet at Twitter.com.

When one has to include the full Tweet in their webapplication, the library has to be upgraded to support the new length.

The update to the Twitter API reference can be found here: https://developer.twitter.com/en/docs/tweets/tweet-updates

The WebHalla based website just needs to read the tweet timeline, so I have updated the following statement to prepare for the 280 character tweets:
Dim sURL : sURL = API_BASE_URL + "/1.1/statuses/user_timeline.json" & "?screen_name=" & sUsername & "&count;=" & iCount & "&exclude;_replies=" & LCase(bExcludeReplies) & "&include;_rts=" & LCase(bIncludeRTs)
And changed it to:
Dim sURL : sURL = API_BASE_URL + "/1.1/statuses/user_timeline.json" & "?screen_name=" & sUsername & "&count;=" & iCount & "&exclude;_replies=" & LCase(bExcludeReplies) & "&include;_rts=" & LCase(bIncludeRTs) &"&tweet;_mode=extended"

Just notice the addition of : &"&tweet;_mode=extended"

When tweet_mode is set to extended, all tweet responses in the JSON data are contained in the "full_text" field instead of the "text" field.

You will notice empty tweets in your webapplication when you do not read the "full_text" field but keep using the "old" "text" field.

To correct this, change the calls
text = URLsBecomeLinks(oTweet.text)
text = URLsBecomeLinks(oTweet.retweeted_status.text)

to:
text = URLsBecomeLinks(oTweet.full_text)
text = URLsBecomeLinks(oTweet.retweeted_status.full_text)

Hope this extends the usefulness of the library.
Kind regards,
Johan
https://www.vansoest.it

Tags:


  • Twitter
  • LinkedIn
  • Facebook
  • Windows Live / Messenger
  • Xbox Live
  • RSS
  • Email