How to build PHP XML-RPC Server, Client and Android application
27 comments
In this article I will show how to build PHP XML RPC server and how to consume provided services with PHP and an Android application as a client. PHP side of things will be built on top of Zend Framework and for Android will be using very thin XML RPC library android-xmlrpc ( http://code.google.com/p/android-xmlrpc/ ).
Assumption is that you already have downloaded Zend Framework and have Android SDK set up (as well as Android emulator). I’ll be using Eclipse both for PHP and Android development. Also, I’ll be using ZF tool for creating project, controllers and models.
We’ll start with building XMLRPC server component.
XMLRPC server component
In your web server’s document root run zf tool with this command: zf create project xmlrpc-test. Afterwards step into this newly created directory xmlrpc-test.
Now we’ll create needed controllers and models.
First run zf create controller Server (which creates our ServerController), then we’ll create our model zf create model Data. Because we’ll also create client side of XMLRPC lets create this controller now to finish out work with zf tool: zf create controller Client.
We should test if our website is running properly, go to http://localhost/xmlrpc-test/public with your browser and you should see image similar to the one below.
Now we’re ready to create our project in Eclipse, open PHP workspace, and go to File->New->PHP project, enter xmlrpc-test as a project name and click Finish. Our project is ready and all files created earlier are in it.
Lets open our Server controller (application/controllers/Server.php) and start building XMLRPC server.
class ServerController extends Zend_Controller_Action
{
public function indexAction()
{
$this->_helper->viewRenderer->setNoRender();
$server = new Zend_XmlRpc_Server();
$server->setClass('Application_Model_Data', 'cf');
echo $server->handle();
}
}
First, we disable our view. We instantiate Zend_XmlRpc_Server and add class which will respond to calls from client, this will be our Application_Model_Data class and we will set its namespace as cf.
We echo the servers handle method, and voila, our very simple and basic XMLRPC server is done.
Now let’s open our model (application/models/Data.php) and create some test method for returning dummy data.
class Application_Model_Data
{
/**
* Test method
*
* @return string
*/
public function test()
{
return 'Hello XMLRPC!';
}
}
This class, Application_Model_Data is classic PHP class, the most important thing here is to notice the comments. They are mandatory, because when call occurs, Zend_XmlRpc_Server will be doing reflection of this class before running it, checking if called method exists and if its arguments are matching defined ones and are correct type. So, we have to define types of all input parameters (none in this test method) as well as method return type.
Let’s write XML RPC client to check if everything is OK so far.
XMLRPC PHP client
Earlier we created ClientController class (located in application/controller/Client.php) with default indexAction method and now we’ll add our code in it.
class ClientController extends Zend_Controller_Action
{
public function indexAction()
{
$client = new Zend_XmlRpc_Client('http://localhost/xmlrpc-test/public/server/');
try {
$data = $client->call('cf.test');
$this->view->data = $data;
} catch (Zend_XmlRpc_Client_HttpException $e) {
require_once 'Zend/Exception.php';
throw new Zend_Exception($e);
} catch (Zend_XmlRpc_Client_FaultException $e) {
require_once 'Zend/Exception.php';
throw new Zend_Exception($e);
}
}
}
First we instantiate Zend_XmlRpc_Client and provide its constructor URI of our XML RPC server. Then we try to make a call to a test method (‘cf’ is a namespace defined for our Application_Model_Data class). We’ll forward returned data to our view.
Our view is located in application/views/scripts/client/index.phtml. In it we are only echoing data returned from our test method.
<h1>Via XMLRPC</h1> <?php echo $this->escape($this->data); ?>
If we run http://localhost/xmlrpc-test/public/client in our browser we should get something like this:
Let’s add another method to our Application_Model_Data class which will be expecting single Integer parameter and it will be returning an associative array.
/**
* Fetches data
*
* @param integer $num
* @return array
*/
public function getData($num)
{
$data = array();
for ($a = 0; $a < $num; $a++) {
$data[] = array(
'title' => 'Codeforest.net',
'number' => $a + 1,
'datetime' => date('Y-m-d H:i:s')
);
}
return $data;
}
Method is called getData (yes, very creative) and it’s pretty simple. Again, notice the comments with defined @param and @return lines.
We also have to upgrade our ClientController class and instead of calling cf.test method will be calling cf.getData method. We only have to supstitute one line (7th):
$data = $client->call('cf.test');
with this one:
$data = $client->call('cf.getData’, 15);
Everything else in the ClientController class stays the same.
We have to update our view script with something like this:
<h1>Via XMLRPC</h1> <?php if (count($this->data) > 0):?> <ul> <?php foreach ($this->data as $row):?> <li><?php echo $this->escape($row['number'])?> - <?php echo $this->escape($row['title'])?>, <?php echo $this->escape($row['datetime'])?></li> <?php endforeach;?> </ul> <?php endif; ?>
Again, we go to our browser to test http://localhost/xmlrpc-test/public/client. Result is similar to:
This concludes our PHP and Zend Framework part of the article.
XMLRPC Android client
If using Eclipse switch to Android workspace (File->Switch Workspace, pick your Android workspace).
After you have switched workspace go to File->New->Android Project, enter project name, select build target and fill the rest of the properties.
Download Android XML-RPC client library from http://code.google.com/p/android-xmlrpc/.
Create new package in our project (right mouse click on project name in Package explorer and select New->Package). Name this package org.xmlrpc.android and copy files form archive directory android-xmlrpc/src/org/xmlrpc/android into this newly created package.
Now our directory structure should be similar to picture below:
Because we’ll be needing internet connection (to connect to our XML-RPC server) we need to add internet permission to our android manifest file. Open AndroidManifest.xml and in raw XML view add next line just before closing manifest tag:
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
In our example we’ll be using default layout file res/layout/main.xml but we’ll add an ID to its TextView element so that we can fill it out with received data. So open res/layout/main.xml file and locate TextView element. Add an android.id attribute with @+id/text_view value to it:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<TextView
android:id="@+id/text_view"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:text="@string/hello"
/>
</LinearLayout>
Now we can start building our Android Client. Open Client.java in our com.cf.xmlrpc package and enter:
public class Client extends Activity {
private XMLRPCClient client;
private URI uri;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
uri = URI.create("http://10.0.2.2/xmlrpc-test/public/server/");
client = new XMLRPCClient(uri);
TextView textView = (TextView) findViewById(R.id.text_view);
}
}
First, we create class variables which will hold our XMLRPC Client and URI for our server. We can access this variables throughout our class.
In onCreate method we assign our uri variable URI object. As you can see we are using 10.0.2.2 address to access our own local web server. 127.0.0.1 or localhost is used by the underlying linux OS on emulator.
Then we create our XMLRPCClient and give its constructor our uri variable.
We’ll also get reference to TextView element of our layout where we’ll display our results.
If Eclipse is signaling for some error due to not having imported needed classes press Ctrl+Shift+O, this will import all needed classes automatically.
Next, we’ll create method which will call test method on our XML-RPC server (built earlier with Zend Framework).
private String testMethod() {
String text = "";
try {
text = (String) client.call("cf.test");
} catch (XMLRPCException e) {
Log.w("XMLRPC Test", "Error", e);
text = "XMLRPC error";
}
return text;
}
We’re using try – catch block to catch errors and to deal with them. After creating this method we have to call it from onCreate method and display its return value to TextView element. Our modified Client activity class should look like this:
public class Client extends Activity {
private XMLRPCClient client;
private URI uri;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
uri = URI.create("http://10.0.2.2/xmlrpc-test/public/server/");
client = new XMLRPCClient(uri);
TextViewtextView = (TextView) findViewById(R.id.text_view);
textView.setText(testMethod());
}
private String testMethod() {
String text = "";
try {
text = (String) client.call("cf.test");
} catch (XMLRPCException e) {
Log.w("XMLRPC Test", "Error", e);
text = "XMLRPC error";
}
return text;
}
}
We are ready to test our Android client. Select Run->Run configurations and create new Android application configuration for our project:
After the emulator boots up we should have something similar to this:
Hoorah! Our Android client is using our XML RPC web service!
Lets now create method which will call our other server function getData.
private String getDataMethod(int num) {
String text = "";
try {
Object[] data = (Object[]) client.call("cf.getData", num);
for(Object o: data) {
HashMap map = (HashMap) o;
text = text + "'datetime' => " + map.get("datetime") + ", 'number' => " + map.get("number") + ", 'title' => " + map.get("title") + "\n\n";
}
} catch (XMLRPCException e) {
Log.w("XMLRPC Test", "Error", e);
text = "XMLRPC error";
}
return text;
}
Method we are calling (cf.getData) expects one parameter (integer) and returns an associative array (from PHP’s perspective). In Java we received array with map items.
If you are having trouble figuring out what your custom XML RPC service is returning you be sure to check out great post at Inchoo. It describes how to parse the data returned from XMLRPC.
Next step is to switch method calls in onCreate method:
textView.setText(testMethod());
to this one:
textView.setText(getDataMethod(12));
After saving and running (again select Run->Run configurations) our changed Android client we should have on the emulator something like:
And that’s it. We covered all the elements necessary to build PHP XML-RPC Server, Client and Android application that will harvest it.
Feel free to leave a comment, a question or a critique. Also feel free to request a follow up or an article with stuff that interests you.
To get even more excellent content, you can follow me on Twitter.
27 Responses to “How to build PHP XML-RPC Server, Client and Android application”
-
-
jas says:
Any idea why I would be getting 404 for the public/client and public/server folders?
They didn’t seem to be get created when creating the initial project.
-
jas says:
Roger.
If I try to run it again I receive a ‘This project already has a controller named Client &/or Server’.
-
jas says:
I think it might be the zend installation. I installed from source from http://www.zend.com/core/start.
Went into the htdocs folder, ran the commands to create a new project, new server controller and new client controller.
The test page came up fine, I then went though and added the code to the files you indicated however the application/controller/Client.php and application/controller/Server.php were named ClientController.php and ServerController.php (not sure if that makes much of a difference).
And from what I understand is that the bootstrap.php should then load the newly registered client and server controllers from their ‘virtual folder’s correct?
-
jacinto says:
Awesome tutorial…. thank you very much!
-
Soho bar says:
Well, not that bad… Pretty good job for a rookie
-
Seba says:
hi, very good tutorial, i’ve have just one problem, when i am trying to use
the URL of my local host always get an error from the android application “HTTP status code: 500 != 200″.i’ve tried to use :
10.0.2.2
127.0.0.1
192.168.150.121 (my IP)but nothing seems to work, same error always, but when i use the url from your
example “http://www.lukapeharda.com/demos/xmlrpc-test/public/server/” it works
just fine.i hope you can give me some advice.
-
Seba says:
thanks for your response Luka, the application runs ok, the problem is:
When I use this URL:
$client = new Zend_XmlRpc_Client(‘http://www.lukapeharda.com/demos/xmlrpc-
test/public/server/’);works ok
but, when i put this URL:
$client = new Zend_XmlRpc_Client(‘http://localhost/xmlrpc-
test/public/server/’);It doesn’t.
Could be a problem with Zend library? I am using the code downloaded from the
web just for check and i have the same problem. The only three diferences that I can
see are:Server.
Zend library (maybe)
ServerControler (maybe is diferent the one in your web than the one in the example?)Thx
-
aivaras says:
Nice tutorial, but I have one issue. Please, open this link – http://www.lukapeharda.com/demos/xmlrpc-
test/public/server/ – it shows:
ServerController faultCode 630
faultStringUnable to read requestI get same thing on my localhost and not sure how to solve it. Any hints would be very appreciated, please.
-
aivaras says:
Hi Luka,
Ignore my previous message-question. I have sorted myself, just wanted to see a result too fast. I can see I have same issue with pointing to localhost – it throws me an exception. I’ll try to figure out myself and let you all guys know what works for me.Anyway, thanks for good tutorial. Next stage – android implementation
Keep in touch -
zzgl says:
Hi;
I want to write an android program but I’m beginner so I dont understand something.can you help me.? -
zzgl says:
falsefalsetruenofalse,
THAT IS SAP PART AND
package com.pcis.Planet;
import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;public class Proje01Activity extends Activity {
/** Called when the activity is first created. */
private static final String SOAP_ACTION = “ZpcisMuratkWs01″;
private static final String METHOD_NAME=”ZpcisMuratkWs01″;
private static final String NAMESPACE=”urn:sap-com:document:sap:rfc:functions”;
private static final String URL=”http://pcissp09.pcis.com.tr:8090/sap/bc/srt/wsdl/sdef_ZPCIS_MURATK_TICKET/wsdl11/ws_policy/document?sap-client=900″;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
Button btTest = (Button) this.findViewById(R.id.btTest);btTest.setOnClickListener(btTestListener);
}
public Button.OnClickListener btTestListener = new Button.OnClickListener() {
public void onClick(View v) {
try {
// Create SOAP request
SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
SoapEnvelope.VER11);
envelope.setOutputSoapObject(request);
HttpTransportSE androidHttpTransport = new HttpTransportSE(URL);
androidHttpTransport.call(SOAP_ACTION, envelope);// Get response from envelope
Object result = envelope.getResponse();// Display result
Toast.makeText(Proje01Activity.this, result.toString(),
50000).show();} catch (Exception e) {
e.printStackTrace();
}
}
};
}
THAT İS MY ANDROİD CODE
CAN YOU TELL ME WHERE AM I WRONG.
BEST REGARDS -
zzgl says:
THAT SAP PART SORRY
-
zzgl says:
I CANT SEND SAP PART.
-
Akhil N K says:
Hi,
Awesome tutorial to start with…
Can you explain the same a little bit deeper by qouting an example which send login information to the web service and then the webservice checks the DB for the existence of the user and responds as required? That would add more to the value of this article. -
Lee sea wuyhs says:
This post is very good.
Thanks you!










Nice article, but I’d strongly suggest using a JSON-RPC setup. A big disadvantage of XML-RPC is the amount of data it generates. This is especially important when working on mobile systems.
For both Zend and Android JSON-RPC libraries are available.