KSoap with PHP Tutorial
This post is for:
You: developing a BlackBerry application in KSoap2 with PHP as the server
If that doesn’t describe you, don’t read this post!
If that does describe you, hope you enjoy!
The first step is to preverify your KSoap jar file. Copy ksoap2-j2me-core-2.1.2.jar to C:\Program Files\Eclipse\plugins\net.rim.eide.componentpack4.5.0_4.5.0.16\components\bin
Make sure the JDK is in your PATH environment varaible.
Then run:
preverify -classpath "JDE_PATH_HERE\lib\net_rim_api.jar" "ksoap2-j2me-core-2.1.2.jar"
Preverify put a new jar into an “output” directory in that folder. Copy that to where you put the original jar.
Now add that jar in your eclipse project by clicking on your project properties and going to “Java Build Path” – make sure you click on “Order and Export” and check the box that tells it to export it.
Well here’s where the rubber meets the road, you need KSoap to talk to PHP. I created a “Service” class which handles all the communication with the server:
import java.io.IOException; import org.ksoap2.SoapEnvelope; import org.ksoap2.SoapFault; import org.ksoap2.serialization.SoapObject; import org.ksoap2.serialization.SoapSerializationEnvelope; import org.ksoap2.transport.HttpTransport; import org.xmlpull.v1.XmlPullParserException; public class Service { public static final String action = "http://keyringlabs.com/Login"; public static final String namespaceRoot = "keyringlabs.com"; public static final String webroot = "http://192.168.1.2/bbpointofsale.com/"; public String errorMessage; public String key; public String transactionID; private HttpTransport transport; private SoapSerializationEnvelope envelope; public Service() { transport = new HttpTransport(webroot + "bb/service/index.php"); transport.debug = true; envelope = new SoapSerializationEnvelope(SoapEnvelope.VER10); key = null; }
A request is made by setting parameters and getting back a parameter, getting back more than one parameter is left as an exercise for the reader. Here’s what I’ve done:
public boolean ProcessLogin(String email, String password) { System.err.println("ProcessLogin"); errorMessage = ""; String namespace = "urn:" + namespaceRoot + ":login"; SoapObject message = new SoapObject(namespace, "login"); message.addProperty("email", email); message.addProperty("password", password); envelope.bodyOut = message; String soapAction = namespace + "#login"; try { transport.call(soapAction, envelope); } catch (IOException e) { e.printStackTrace(); System.out.println("error: "+e.getMessage()); errorMessage = e.getMessage(); System.out.println("response: "+transport.responseDump); return false; } catch (XmlPullParserException e) { e.printStackTrace(); errorMessage = e.getMessage(); System.out.println("response: "+transport.responseDump); return false; } try { SoapObject result = (SoapObject) ((SoapObject)envelope.getResponse()).getProperty(0); key = hackToGetResponse("serviceToken", result.toString()); if (key.length() > 0) { System.out.println("KEY:" + key); return true; } else { } } catch (SoapFault e) { errorMessage = e.getMessage(); System.out.println("response: "+transport.responseDump); return false; } catch (Exception e) { errorMessage = e.getMessage(); System.err.println("response: "+transport.responseDump); return false; } return false; }
hackToGetResponse is necessary because the return of the PHP page the request is sent to is difficult to get at through KSoap. This is hackToGetResponse:
public String hackToGetResponse(String key, String response) { System.out.println("hackToGetResponse:" + response); String start = "anyType{key=" + key + "; value="; String end = "; }"; if (response.indexOf(start) == -1 || response.indexOf(end) == -1) return ""; System.out.println("hackToGetResponse:" + "response.substring(0, " + response.indexOf(start) + ").substring(0, " + response.indexOf(end) + ");"); response = response.substring(response.indexOf(start) + start.length()); response = response.substring(0, response.indexOf(end)); if (response.indexOf("anyType{}") != -1) return ""; return response; }
And finally, the PHP code:
<?php $server = new SoapServer(null, array('uri' => "urn:keyringlabs.com")); $server->addFunction("login"); function login($email, $pass) { if (strlen($email) == 0) { return Array('serviceToken' => ''); } elseif (strlen($pass) == 0) { return Array('serviceToken' => ''); } else { $objMerchant = Merchant::LoadByEmailPassword($email, $pass); if ($objMerchant == null || $objMerchant->Id < 1) { return Array('serviceToken' => ''); } else { $key = uniqid(); $objSess = new Merchantsessions(); $objSess->MerchantID = $objMerchant->Id; $objSess->ServiceToken = $key; $objSess->Save(); } } $result = Array('serviceToken' => $key); return $result; } ?>
That’s it, a BlackBerry application that communicates with a PHP application with very little legwork. I hope this is useful to some people, it was a long journey for me to arrive at this code.
When I have some time I will make the Service class multi-threaded (as it should be being that it does network connections), I will post an update here when I’ve done that.
December 8th, 2009 at 5:38 AM
For those curious the ORM objects used in the example PHP code were all automatically generated by QCubed. http://www.petetracey.com/2009/09/qcubed-rocks/
January 28th, 2010 at 10:17 AM
very good!!!
php include missing?
January 29th, 2010 at 5:13 AM
I left out the QCubed includes from this tutorial because they have nothing to do with KSoap2 and PHP Soap services. You can do whatever you want with the values you get from the blackberry, and send it back whatever you want. I just happen to use QCubed. In case someone is using QCubed though, all you need is the prepend.inc.php include.
One thing I should probably mention that is pretty important, though, is that the SoapServer object is only available if you have enabled “–enable-soap” for your PHP build. So if you’re getting errors that SoapServer doesn’t exist, it isn’t a missing include, it’s a PHP build missing that option.
November 23rd, 2010 at 9:33 PM
nice tutorial!!
btw i want to know about if “$result” in PHP is an array,an array of object ,or an object.how can we passing that array?would you tell with an example?
thanks,
tian
June 8th, 2011 at 4:18 AM
The preverification step required for ksoap2, i noticed you used net.rim; if i were to preverify for a j2me app how do i go about preverifying for this platform?
November 28th, 2011 at 2:27 PM
@tian
This line associates the function with the SOAP that will be sent back to the BlackBerry. By returning a PHP array the SOAP library takes over and pushes it into XML that is supposedly a standard SOAP message. However I had to do that hack just to get to that single value, think there’s something wrong. The gist of the article though is the pre-verify step, I noticed people all over the net banging their heads against the wall because they missed that step.
That said, it is really better to use one of the cross-platform libraries where you can write a single code base and it will cross-compile for iOS, Android, and BlackBerry devices. Unless you’re doing something more low-level than permitted by those APIs, which in this case was interfacing with credit card swipe peripherals. That project is pretty much on hold for now though.
November 28th, 2011 at 2:31 PM
@Oladipo Olasemo
I’m guessing just about the same process as net.rim just with the corresponding classes in j2me, I think net.rim just extends those classes.