Paypal Express example with Coldfusion 8

Posted on Tuesday, November 3rd, 2009 at 3:50 pm

If you are building an ecommerce site it’s likely that you’re using paypal as your payment processing method.  Paypal’s documentation is not bad, but for someone creating a paypal checkout with paypal’s Website Payments Pro package, the documentation can be somewhat overwhelming.  Once you get the hang of it, this documentation will be indispensable.

So what I’m going to explain is paypal’s express checkout feature in the Website Payments Pro package offered.  This is the paypal button that is on the cart of the website.  When clicked the user is redirected to paypal where they log into their account, choose their payment method, are then returned to the cart where they proceed to checkout. My quick disclaimer is that this is the quick and easy way of doing this.  This is just to simplify the process, not how it should actually be implemented on a production site.

First

You need to set up a developer account at developer.paypal.com. Then create a couple test accounts, one for a business and the other for a personal account. This is all pretty straight forward stuff. If you have trouble paypal also has documentation on setting up accounts in the sandbox. During this process you will be issued a Test Account, API Username, API Password, and a Signature. This information will be used when making calls to paypals server.

Second

You need a shopping cart with the paypal button on it. I’ll assume that you have this.

Third (Our form for the cart)

<cfform name=”ppExpForm” method=”post” action=”#CGI.SCRIPT_NAME#?ppExp=true”><input type=”hidden” name=”PAYMENTACTION” value=”Sale”>
<input type=”hidden” name=”AMT” value=”52.00″>
<input type=”hidden” name=”RETURNURL” value=”http://www.yoururl.com/cart.cfm”>
<input type=”hidden” name=”CANCELURL” value=”http://www.yoururl.com/cart.cfm”>
<input type=”hidden” name=”METHOD” value=”SetExpressCheckout”>
<input type=”image” name=”paypalSubmit” src=”https://fpdbs.paypal.com/dynamicimageweb?cmd=_dynamic-image” alt=”Paypal” border=”0″ />

</cfform>

There is no cart in this form, but it should be.  What we have here is the paypal button at the very bottom.  The source for this image is paypal.  In the documentation you can find the specifics for using this button, but to place it on your page you can use the above code.  Everything else here is hidden form fields that contain the values that we need to send to paypal.  I’ll run through each.

User, pwd, and signature are all values that you retrieved when you set up your developer account.  This is kinda like logging in with paypal.  This just tells paypal who you are.  Also note that I’ve set these values in the Application scope as this is data that you should keep secure so it is best kept in the Application.cfc file.  This also allows you to reuse it easily.  Because they are part of the APPLICATION scope they are not included as hidden form fields. But you can see that they are passed in as variables in the code in the fourth step. Each request made to paypal will have to contain this data.  At the time of this writing the version is 52.  Paymentaction can be several things, but we’ll assume that you’re selling so it is set to Sale.  This tells paypal what type of transaction you are requesting.  Amt is the amount to be charged.  The returnurl can go anywhere you want it to go, but for us it makes the most sense for it to return to the cart so we can check the data that is sent back.  The cancelurl is the url the user will be directed to if they cancel out of paypal.  Again we have it coming back to the cart.  And lastly the all important method is set.  Paypal has three methods for the express.  The first is ‘SetExpressCheckout’.  This gets the process initiated.

The last thing I’ll mention is that the action of our form is submitting to itself.  Because of this I’ve set a variable into the URL as ppExp=true.  This is just to indicate to us when the page reruns that paypal express has been used as the payment method and we need to gather the hidden form values and send it to paypal to get this ball rolling.

Fourth (The Submission)

The idea is that when we click the paypal express button we rerun the cart.cfm page. When this happens we need to send our data to paypal and abort the processing on the page. So at the top of our cart.cfm page we need the following code.

<!—******************************  SEND USER TO PAYPAL  ********************************—>
<cfif CGI.request_method eq “POST” AND isdefined(‘URL.ppExp’) AND URL.ppExp eq “true”><!— set our values to send to paypal into a struct —>
<cfset VARIABLES.ppVals = structnew()>

<cfset VARIABLES.ppVals.method = FORM.METHOD>
<cfset VARIABLES.ppVals.paymentAction = FORM.PAYMENTACTION>
<cfset VARIABLES.ppVals.user = “#APPLICATION.username#”>
<cfset VARIABLES.ppVals.pwd = “#APPLICATION.pwd#”>
<cfset VARIABLES.ppVals.signature = “#APPLICATION.signature#”>
<cfset VARIABLES.ppVals.version = “#APPLICATION.version#”>
<cfset VARIABLES.ppVals.amt = FORM.AMT>
<cfset VARIABLES.ppVals.returnurl = FORM.RETURNURL>
<cfset VARIABLES.ppVals.cancelurl = FORM.CANCELURL>

<!— call the method to initiate the pp request —>
<cfinvoke component=”path.to.pp_checkout” method=”ppPost” requestdata=”#VARIABLES.ppVals#” serverurl=”https://api-3t.sandbox.paypal.com/nvp” returnvariable=”VARIABLES.response”>

<!— send data to method to return it as a struct —>
<cfinvoke component=”path.to.pp_checkout” method=”getNVPResponse” nvpString=”#URLDecode(VARIABLES.response)#” returnvariable=”VARIABLES.responseStruct”>

<!— check if the connection with paypal was a success —>
<cfif isdefined(‘VARIABLES.responseStruct.ack’) AND VARIABLES.responseStruct.ack eq “success”>
<!— send the user to paypal login —>
<cflocation url=”https://www.sandbox.paypal.com/cgi-bin/webscr?cmd=_express-checkout&token=#VARIABLES.responseStruct.token#”  addtoken=”false”>
<cfelse>
Sorry. There was a problem connecting with the PayPal server.
</cfif>
</cfif>

What we need to do is make a request to paypal.  We do this by calling the ‘ppPost’ method we have stored in a cfc.  If paypal accepts everything we will get back a token.  The data we get back is in the url so we need a way to parse it and set that data into a struct that is easier to work with.  I have the code for both cfcs, which were ripped right from paypals coldfusion examples in the docs.  I cleaned them up a little bit, but they work quite well right out of the box.

ppPost Method

<!— *****************************  POST DATA TO PAYPAL  ***************************** —>
<cffunction name=”ppPost” displayname=”Paypal Post Data” description=”Posts data to paypal and accepts the return data” access=”public” output=”false” returntype=”Any”>
<cfargument name=”requestdata” displayName=”Request Data” type=”struct” hint=”This struct holds all of the data we need to send to paypal to initiate the Paypal express checkout” required=”true” />
<cfargument name=”serverurl” displayName=”Server URL” type=”string” hint=”This is the url we are posting to” required=”true” /><!— run the http post to paypal —>
<cfhttp url=”#ARGUMENTS.serverurl#” method=”post”>
<cfloop collection=”#requestData#” item=”requestKey”>
<cfhttpparam name=”#requestKey#” value=”#ARGUMENTS.requestData[requestKey]#” type=”formfield” encoded=”true”>
</cfloop>
</cfhttp>

<!— return the content —>
<cfreturn cfhttp.FileContent>

</cffunction>

getNVPResponse Method

<!— *****************************  CONVERT PAYPAL DATA TO STRUCT  ***************************** —>
<cffunction name=”getNVPResponse” displayname=”Response to Struct” description=”Returns paypals response as a struct that I can work with.” output=”false” access=”public” returntype=”struct”>
<cfargument name=”nvpString” type=”string” required=”yes” >

<cfset var responseStruct = StructNew()>
<cfset var keyValStruct = StructNew()>
<cfset var keys = “”>
<cfset var Values = “”>
<cfset nvpArray = ArrayNew(1) >
<cfset keyArray = ArrayNew(1) >
<cfset valueArray = ArrayNew(1) >
<cfset key = “”>
<cfset value = “”>
<cfset currentValue = “”>
<cfset tempVal = “”>
<cfset count = 1 >
<cfset tempvalue = “”>
<cfset  lennvp =  0>

<cfloop from=”1″ to=”#len(nvpString)#” index=”i”>
<cfset lennvp = lennvp + 1>
<cfset index = 1>

<cfif #Mid(nvpString, i, 1)# is not “&”>
<cfset tempVal = tempVal & #Mid(nvpString, i, 1)#>
</cfif>

<cfif #Mid(nvpString, i, 1)# is “&” OR “#lennvp#” is “#len(nvpString)#”>
<cfset nvpArray[count] = #trim(tempVal)#>
<cfset count =  count + 1>

<cfset tempVal = “”>
</cfif>
</cfloop>

<cfloop from=”1″ to=”#ArrayLen(nvpArray)#” index=”i”>
<cfset currentValue = #nvpArray[i]#>

<cfloop from=”1″ to= “#len(currentValue)#” index=”i”>
<cfif #Mid(currentValue, i, 1)# is “=”>
<cfbreak>
<cfelse>
<cfset tempValue = tempValue & #Mid(currentValue, i, 1)#>
</cfif>
</cfloop>

<cfset keyArray[index] = #trim(tempValue)#>
<cfset index = #index# + 1>
<cfset tempValue = “”>
</cfloop>

<cfset vals = “”>
<cfset key = “”>

<cfloop from=”1″ to=”#ArrayLen(nvpArray)#” index=”i”>
<cfset vals  = #nvpArray[i]# >
<cfset key = #keyArray[i]#>
<cfset value = #RemoveChars(vals ,1, (len(key) +1))#>
<cfset valueArray[i] = value>
<cfset x = StructInsert(responseStruct,#trim(key)#,#trim(value)#)>
</cfloop>

<cfreturn responseStruct>

</cffunction>

So with this token we can repost to paypal using the token to open a transaction.  The user will be sent to paypal where they will login and choose their payment type.  Since this is in the sandbox you should be able to enter the fake personal account you previously set up within the paypal sandbox.  After confirming everything you are sent back to the cart.

At any point here you can dump the contents of the getNVPResponse Method by using <cfdump var=”#VARIABLES.responseStruct#”>.  This will let you see exactly what paypal is returning to you.

Fifth (Who is the user?)

So the customer has logged in with their paypal account and been sent back to paypal. Now we need to use our new shiny token paypal sent us to get the information we need about our customer. To do this we need to make another post using the same ppPost method to make the post and the getNVPResponse method to parse the data sent back. But this time we are going to run the paypal’s GetExpressCheckoutDetails method.

<!— **********************  IF THE USER HAS RETURNED FROM PAYPAL  ********************** —>
<cfif isdefined(‘URL.token’) AND isdefined(‘URL.payerid’)>
<!— set our values to send to paypal into a struct —>
<cfset VARIABLES.ppVals = structnew()>

<cfset VARIABLES.ppVals.method = “GetExpressCheckoutDetails”>
<cfset VARIABLES.ppVals.user = “#APPLICATION.username#”>
<cfset VARIABLES.ppVals.pwd = “#APPLICATION.pwd#”>
<cfset VARIABLES.ppVals.signature = “#APPLICATION.signature#”>
<cfset VARIABLES.ppVals.version = “#APPLICATION.version#”>
<cfset VARIABLES.ppVals.token = “#URL.token#”>

<!— call the method to initiate the pp request —>
<cfinvoke component=”path.to.pp_checkout” method=”ppPost” requestdata=”#VARIABLES.ppVals#” serverurl=”https://api-3t.sandbox.paypal.com/nvp” returnvariable=”VARIABLES.response”>

<!— send data to method to return it as a struct —>
<cfinvoke component=”path.to.pp_checkout” method=”getNVPResponse” nvpString=”#URLDecode(VARIABLES.response)#” returnvariable=”VARIABLES.responseStruct”>

<!— if we get back the details set them into the user session —>
<cfif isdefined(‘VARIABLES.responseStruct.ack’) AND VARIABLES.responseStruct.ack eq “success”>
<cfset SESSION.user.countryCode = VARIABLES.responseStruct.countrycode>
<cfset SESSION.user.email = VARIABLES.responseStruct.email>
<cfset SESSION.user.firstName = VARIABLES.responseStruct.firstname>
<cfset SESSION.user.lastName = VARIABLES.responseStruct.lastname>
<cfset SESSION.user.payerid = VARIABLES.responseStruct.payerid>
<cfset SESSION.user.payerstatus = VARIABLES.responseStruct.payerstatus>
<cfset SESSION.user.shippingCountryCode = VARIABLES.responseStruct.shiptocountrycode>
<cfset SESSION.user.shippingCountryName = VARIABLES.responseStruct.shiptocountryname>
<cfset SESSION.user.shippingName = VARIABLES.responseStruct.shiptoname>
<cfset SESSION.user.shippingCity = VARIABLES.responseStruct.shiptocity>
<cfset SESSION.user.shippingState = VARIABLES.responseStruct.shiptostate>
<cfset SESSION.user.shippingAddress = VARIABLES.responseStruct.shiptostreet>
<cfset SESSION.user.shippingZipCode = VARIABLES.responseStruct.shiptozip>
<cfset SESSION.user.token = VARIABLES.responseStruct.token>

<!— move the user to the billing and shipping page —>
<cflocation url=”http://www.yoursite.com/place_order.cfm?ppExp=true” addtoken=”false”>
<cfelse>
Sorry. There was a problem connecting with the PayPal server.
</cfif>
</cfif>

First we check if we have been redirected to our cart page from paypal. We can do this by checking for a token and a payer id that was returned from paypal in the url. If so we can use our token to submit a new request to paypal to get some basic information about the user who just logged in. We create a new struct just like we did before, except this time we include the token and the method ‘GetExpressCheckoutDetails’. We use the same method to post it to paypal, and the same method to parse the url when we get our response from paypal. If we get the data from paypal successfully we need to set our data into our user’s session. We are doing this so we can have the data at hand to output on the place order page we are sending the user to. So after setting our data into the session we can redirect the user to our place_order.cfm page where they can review their cart and finalize the checkout. Again, we will pass ‘ppExp=true’ in the url so we know that our user is using paypal express.

Sixth (Show me the moolah!!)

On this page we would show our user the contents of their cart, give them a final chance to make changes to it, and allow them to submit their order. To do this we have a place order button in a form called ‘ppExpSubmit’ that submits to itself. So at the top of our page we need to check if this page has been submitted by the user to finalize their purchase.

<!— *************************************  PAYPAL EXPRESS  ************************************* —>
<cfif CGI.request_method eq “POST” AND isdefined(‘FORM.ppExpSubmit’)>
<!— set our values to send to paypal into a struct —>
<cfset VARIABLES.ppVals = structnew()>

<cfset VARIABLES.ppVals.method = “DoExpressCheckoutPayment”>
<cfset VARIABLES.ppVals.user = “#APPLICATION.username#”>
<cfset VARIABLES.ppVals.pwd = “#APPLICATION.pwd#”>
<cfset VARIABLES.ppVals.signature = “#APPLICATION.signature#”>
<cfset VARIABLES.ppVals.version = “#APPLICATION.version#”>
<cfset VARIABLES.ppVals.token = “#SESSION.user.token#”>
<cfset VARIABLES.ppVals.payerid = “#SESSION.user.payerid#”>
<cfset VARIABLES.ppVals.paymentaction = “Sale”>
<cfset VARIABLES.ppVals.amt = “#SESSION.total#”>

<!— call the method to initiate the pp request —>
<cfinvoke component=”#APPLICATION.checkoutCfcPath#.pp_checkout” method=”ppPost” requestdata=”#VARIABLES.ppVals#” serverurl=”https://api-3t.sandbox.paypal.com/nvp” returnvariable=”VARIABLES.response”>

<!— send data to method to return it as a struct —>
<cfinvoke component=”#APPLICATION.checkoutCfcPath#.pp_checkout” method=”getNVPResponse” nvpString=”#URLDecode(VARIABLES.response)#” returnvariable=”VARIABLES.responseStruct”>

<!— make sure the transaction was finalized —>
<cfif VARIABLES.responseStruct.ack eq “success”>
<!— redirect the user to the order confirm page —>
<cflocation url=”http://www.yoursite.com/confirmation.cfm” addtoken=”false”>
<cfelse>
<!— output an error message —>
</cfif>

<!— stop further processing —>
<cfabort>

</cfif>

</cfif>

If our user has submitted their order we need to make one last request to paypal.  The method we need to send this time is the ‘DoExpressCheckoutPayment’.  Once again create a struct and set the required information into it and send it through the ppPost method and then parse the URL with the getNVPResponse method.  Now check if the transaction was a success and if so give the user some type of confirmation.  In this case we’re moving them to a page called confirmation.cfm.

That’s it.  Once again you can do much more than what I’ve demonstrated here.  But for a basic sale this will do the job.  However, keep in mind that you should consider writing the code a little more efficiently for the sake of reuse, and at any point during this process the responses that come back through paypal can be dumped onto the screen so you can know exactly what paypal is returning to you.  Otherwise I hope this helps.

CategoryColdfusion
25 Responses to “Paypal Express example with Coldfusion 8”
  1. Wildcat says:

    I don’t know where you found those code examples – Lord knows I looked high and low through PayPal and Cold Fusion for *anything* like that and couldn’t – and you have made me a very happy camper (providing this works for me)!

    Your timing on posting this was perfect! Just 10 days later it’s saving my bacon, late on a Friday the 13th when I don’t have time for anymore hair-pulling at the over-engineering of the Paypal documentation team.

    Goodness! I’ve spent almost two days just trying to figure out the wayward garbage they call documentation – and I’m a MENSA member and have been programming in other languages for over 30 years and Cold Fusion since 1996, so it’s not like I’m a newb or an idiot!

    Thank you thank you thank you! May life hand you roses and all the riches you desire!

    Wildcat

  2. Matthew says:

    Glad to have helped wildcat. Hope it works. I simplified this from my original code, so if you do run into any problems (and hopefully you won’t) feel free to post any corrections and I’ll update the code for future users.

  3. Marty says:

    I’m a nube and I’m attempting to follow. I’m trying to run your example and I’m getting an error “Could not find the ColdFusion Component or Interface path.to.pp_checkout.” Although I see ti in your functions, I don’t see it defined in your code, or the code in the PayPal CF examples… Help!

  4. Matthew says:

    Hi Marty. The ‘path.to.pp_checkout’ is a dot notation path to the component that contains the ‘ppPost’ method and the ‘getNVPResponse’ method. Just in case you’re not familiar with dot notation you can always create a component called ‘pp_checkout.cfc’ with the two methods (‘ppPost’ and ‘getNVPResponse’) inside of it in the same directory as the .cfm page that is calling the component. If you put the .cfc component in the same directory as the calling .cfm file the tag will be changed to the following:

    <cfinvoke component=”pp_checkout” method=”getNVPResponse” nvpString=”#URLDecode(VARIABLES.response)#” returnvariable=”VARIABLES.responseStruct”>

    I just got rid of the ‘path.to.’ in the ‘component’ attribute of the tag. Hope this helps.

  5. Pat says:

    I was looking at getNVPResponse and, well, there is a much simpler way to acheive the same result.

    Then just return the structure “returndata”.

    But this article has been a life saver! I so appreciate you posting it. I am starting to finally get my head around this. I am now working on a CFC that will handle all of the calls using your simplified structure approach.

    Once I am done, I will post, if you do not mind for those that needs something to more or less “work out of the box”.

    Thank You

  6. Pat says:

    man now I am a noob

    <cfloop list=”#cfhttp.FileContent#” delimiters=”&” index=”a”>
    <cfset temp=setvariable(“returndata.#gettoken(a,1,”=”)#”,”#URLDecode(gettoken(a,2,”=”))#”)>
    </cfloop>

  7. pukkaman says:

    Thanks Pat. I agree that the getNVPResponse function seemed overly complicated. I dumped it into my cfc straight from the paypal docs and it hasn’t given me any problems, but hey I haven’t had to make edits in it either. So thanks for the code. Awesome.

  8. maxHyper says:

    Thanks for the work!!! This saved me from several late nights! Implemented without a problem!! Great code!

  9. maxHyper says:

    Hi I’m a newbie to paypal and cf, if i wanted to place some code to find out why the payment failed, how would i go about this. where do ifind out what error codes paypal returns and how do i access them using your scripts? i’m not asking you to do work for me, just point me in the right direction!

    Thanks

  10. pukkaman says:

    @maxHyper Yeah, you’ll definitely need to familiarize yourself with the error codes portion of paypals api. You can find them here. It’s actually been a while since I last used paypal, but I’m pretty sure that if there is an error paypal returns the code and maybe even a message. Not knowing where your problem is occurring I can’t say exactly where to dump paypal’s response, but each call to paypal is returned as the ‘returnVariable’ attribute of the cfinvoke tags. So to see at any point what paypal has returned to you, place right after any of these cfinvoke tags a tag. So for example, if you are wanting to see what paypal returns to you after you send payment information you will write ‘ just after the last tag. Hope this helps!

  11. Peter Pham says:

    I followed your sample code. Everything works so far till step 4 (setExpressCheckout). I was able to retrieve the token and redirect customer to Paypal login.
    However, I wonder why the total amount does not show up on Paypal.

  12. Kevin Guto says:

    My friend, you are God Sent. Great Job !

  13. Erik says:

    I used some home brew code for our own version of getNVPResponse, and I am out searching for something better.

    Your code has the same issue as ours as it does not handle PayPal’s updated method of sending strings that contain “&” in the values.

    Example:
    …&SHIPTONAME[15]=Fathers & Sons&SHIPTOSTREET=…

    I am working on my own fix… but would also love to see someone else’s as well since it will most likely be better.

    Thanks.

  14. Jörgen Lundgren says:

    Thank you very much, Pukkaman, and also Pat!

  15. Larry says:

    How would I pass the total and cart items to paypal with this?

  16. Matthew Cook says:

    hmm… it’s been a long time since I’ve worked with paypal. I know the total amount gets passed to paypal via the hidden “amt” field. I don’t think that with paypal express the actual items being purchased are passed. Paypal express only transacts the given amount via the customers preferred payment method. As such only the amount needs to be passed in. Just before the paypal webservice is called the needed values are set into a struct key called ‘ppVals’ in my example’s case. So the example code is ‘set variables.ppVals.amt = FORM.amt’. This is how the amount gets passed to paypal for processing. Hope this helps.

  17. Tara says:

    Hi. I’m am so grateful for this posting. I wish PayPal had a ColdFusion option in their Integration Wizard. Anyway, when I click on my Checkout button, the form submits the page to itself with ppExp=true, but for some reason I get a “The website cannot display this page” HTTP 500 error. The URL is correct in the address bar. Any ideas what I might be doing wrong?? Thank you.

  18. Tara says:

    Nevermind. I had a couple characters that copied/pasted funny. I knew it was something stupid. Crossing my fingers on the rest…thank you so much!

  19. Tara says:

    I’m sorry to bother you again. This is my last post in an attempt to get things working properly. I cannot seem to connect to the PayPal server (I’m using the live one, not sandbox), and the API credentials are set up. However, I found out the server has CF MX7, not 8. Is there anything in this example that I would need to look at that works only in 8 and higher? I’m thinking that’s a possibility.

  20. Matthew Cook says:

    Hi Tara, I took a quick look through the code and nothing immediately stands out as not being supported in CF7. Are you getting any type of error? Just based on your description I assume you are receiving the ‘Sorry. There was a problem connecting with the PayPal server.’ statement? If this is the case can you replace that line with ”, rerun the code, and see exactly what response paypal is sending back. This may help debug the issue. Thanks, Matt.

  21. Tara says:

    Yes, that’s what is happening. I replaced with “, and I just got “. The value for ack isn’t being returned when the form is first submitted. I have the cfc file setup with the functions. I’m going to look at it more in the morning. Maybe something will hit me after looking away from it for a little bit. Thanks, Tara

  22. Paul says:

    Has anyone managed to set currencies? I tried passing this variable steps 4 and 6, like:

    but receive the error

    We have encountered an error. Please try again later. struct
    ACK Failure
    BUILD 1838679
    CORRELATIONID f51d5ec17dde6
    L_ERRORCODE0 10444
    L_LONGMESSAGE0 The transaction currency specified must be the same as previously specified.
    L_SEVERITYCODE0 Error
    L_SHORTMESSAGE0 Transaction refused because of an invalid argument. See additional error messages for details.
    TIMESTAMP 2011-04-13T13:41:49Z
    VERSION 52

    Thank you for any assistance.

    Paul

  23. Paul says:

    sorry, to follow up , I tried to set currencies in steps 4 and 6 like cfset VARIABLES.ppvals.currencycode=”GBP” or other supported currency by writing to a local variable, but I get the error described previously.

    thank you,
    Paul

  24. Garry says:

    Thanks for this, it helped me out quite a bit, however it’s worth noting that PayPal /may/ return “shiptostreet2″ from the getNVPResponse, which needs to be added in the sample above

    Thanks again for the snppets!

  25. Vincent says:

    Thanks for this great tutorial, it save my life ;-)

    I have succefully implement paypal in sandbox mode, but when I go to real Paypal, I get this error message:
    HTTP Status 405 – Request method ‘POST’ not supported

    Have you an idea what could cause this ?

    Also, can I still use the version 52 ?

Leave a Reply

*
(Won't be published) *