You've tried your hand at building mashups, experimented with
a few RESTful Web services, maybe even started your own. Sure, you've
got data sharing working. But how do you make your Web applications
really talk to each other?
In this tutorial, I'll show you how to take your Web applications to
the next level with SOAP, the "powerhouse of Web services", building
high-end Web services with pure PHP.SOAP 101
SOAP is a protocol for applications and servers to communicate with
each other. Its primary use in PHP is exposing Web services and building
Web service clients. As a protocol, it can exchange messages over
HTTP/HTTPS, which helps it get around firewalls that would block other
protocols (eg, Remote Procedure Call).
As an application layer protocol, SOAP is also entirely platform
independent — your PHP Web application can talk to a Java database
server, for example, as long as they both speak SOAP.
SOAP messages are simply XML with some custom namespaces, so they're
fully machine-readable. Libraries are available for every major
language, and working with SOAP Web services is quick, easy and fast.SOAP for PHP
Today we're going to take a look at one of these libraries, NuSOAP. PHP has a few options for SOAP, including a PHP 5 extension, a PEAR package,
and an independent (but very popular) library called NuSOAP. NuSOAP is
the simplest way to get up and running with SOAP, but we could just as
well have used PEAR::SOAP or the extension, and all three are
interoperable — you can consume PEAR::SOAP exposed services with NuSOAP
and vice versa, and scripts using either can happily run alongside each
other.Getting started with NuSOAP
To begin using NuSOAP, first head to the project page
and download a copy of libraries — I'm using version 0.7.2. All
examples should be forwards-compatible, but API changes happen, so check
your library version if you encounter any errors. Drop the contents of
the archive into a folder on your Web server — using /soap under my
docroot. The latest version is compatible with the SOAP extension, but
if you experience "class already declared" errors just disable the SOAP
extension or rename the class in nusoap.php.Your first SOAP request!
We'll start with the SOAP client. SOAP works with servers and clients; servers expose services and clients consume
them. We'll start with a demo of a simple Web service that takes an
argument and returns an array — but with the power of SOAP, we get that
array data locally, almost as if the client was the server, and SOAP
takes care of all the information in between.
Fire up your favourite text editor and type out the following:

call("hello_world", array("name" => "Josh"));
print_r($output);

Save it as hello_world.php in the folder you created earlier. It can
be anywhere, as long as the lib/nusoap.php reference still points to
your NuSOAP library. Do the same for the server:

Save this as hello_world_server.php in the same folder. If it can't
be accessed at that URL in the client script (localhost/soap/...),
change the reference in the client code as needed.
Then load up your Web browser, point it to the SOAP client — eg,
http://localhost/soap/hello_world.php — and run the script. You should
see the following:

Array
(
[data] => Hello World, Josh!
)

That's perfectly normal print_r output — precisely what you would
expect if you returned the array within the same PHP script. Except that
our server script is separate, could be on a different server and could
be running on a totally different platform — SOAP helps gets data from
the server to the client as smoothly as possible.The Server
Let's examine the server for a moment. Here's the code we used to build our server:

In this example, we first load up the NuSOAP library and register the
service we want to expose, naming it "hello_world". We then define this
service as a standard PHP function. At the moment, it does nothing but
return a simple associative array, with the value containing an
argument, $name. The client provides this argument from a
totally separate PHP script and SOAP provides the glue to make sure it
is passed in when the function is called.
HTTP is stateless, and our PHP script will be executed from the top
down whenever a request is made, so each SOAP call (or other script
execution) will be a new request. To check if we have a SOAP call (and
what the SOAP client wants us to do), we have to scan each request for
data. SOAP clients send POST requests, with XML data in the message body
of the request, so we can fetch this raw POST data and pass it to the service() method of the soap_server class. Raw POST data is available in $HTTP_RAW_POST_DATA,
but PHP won't set this unless it has a value, so we use a small hack to
ensure it exists before passing it on to the SOAP server.

We quickly get together the raw POST data, pass it to the SOAP library, and away we go.The Client
The client uses the NuSOAP library, but only because we choose to —
the server could use the PHP SOAP extension or PEAR::SOAP, and could be
hosted anywhere. With the power of SOAP, we're going to take the PHP
function on the server and talk to it through SOAP; we're also going to
receive the result just like any other variable within our script. Have a
look at the code for the client:

call("hello_world", array("name" => "Josh"));
print_r($output);

The client is very basic — we first load up the library, then
establish a connection to the SOAP server at the URL we've provided and
call the "hello_world" service. For testing, we'll print_r the output. The second argument to the $soap->call()
method is an array of parameters to be passed to the service. Notice we
specify 'name' as the array key, the same as the $name argument on the
server's function — this is not necessary as we aren't working with
complex pre-defined services, however, it does hold importance when
consuming slightly more elaborate SOAP services.
The service call returns a value which we then put into $output. If we check that print_r output earlier, it showed we had a perfectly good PHP associative array — [data] => Hello World, Josh! — just as our server's hello_world()
function should have returned. In just a few lines of code, we've
linked together two independent PHP scripts. Now your Web apps are
really talking.Behind the scenes: debugging SOAP
While you make high-level calls to the SOAP libraries, the NuSOAP
library is actually busy generating and parsing XML request messages and
passing them back and forth between server and client. You can easily
examine the message body of your request and the server's response on
the client side, using the request and response
properties of the SOAP client class. These are invaluable in debugging,
and will help you get a better understanding of SOAP internals,
although you may never need it...

Notice we're making a direct POST request and passing all the XML
through. In a HTML form request, that XML would be replaced with
key=value&key=value pairs, which are then translated into elements
of $_POST — this is why we have to request the raw POST data to check
for a SOAP request. The actual XML schema for SOAP messages isn't
important, as the libraries take care of it for us, but read up on the SOAP specifications if you want to take a closer look.Further SOAP
Now that you've built your first SOAP client, experiment with more
complex APIs, or try consuming one of the many SOAP-based APIs
available. If your applications already receive data from other sources,
check if they offer SOAP — its use is very prevalent in enterprise
situations, especially where SOA is encouraged. Finally, if you want to learn more about NuSOAP, one of the authors provides some handy resources.

For the past few days I have been working with SOAP on a number of platforms. I wanted to use NuSoap with PHP5
and here are a few steps which will allow you to do so. As PHP5 has an
inbuilt support for webservices it will clash with the names in nusoap.php. To get over this rename the classsoapclient to soap_client. Also rename the constructorsoapclient to soap_client.

This is all that needs to be done. Once you do this you would be able to run NuSoap with PHP5.

USB_ModeSwitch is (surprise!) a mode switching tool for controlling “flip flop” (multiple device) USB gear.
Several new USB devices (especially high-speed wireless WAN stuff,
they’re expensive anyway) have their MS Windows drivers onboard; when
plugged in for the first time they act like a flash storage and start
installing the driver from there. After that (and on every consecutive
plugging) this driver switches the mode internally, the storage device
vanishes (in most cases), and a new device (like an USB modem) shows up.
The WWAN gear maker Option calls that feature “ZeroCD (TM)”.
As you may have guessed, nothing of this is documented in any form
and so far there are no official Linux drivers available. On the good
side, most of the known devices work out of the box with the available
Linux drivers like “usb-storage” or “usbserial”. That leaves the problem
of the mode switching from storage to whatever the thing is supposed to
do.
Fortunately there are things like human reason, USB sniffing programs
and “libusb”. It is possible to eavesdrop the communication of the MS
Windows driver, to isolate the command or action that does the
switching, and to reproduce the same thing with Linux.
USB_ModeSwitch makes the last step considerably easier by taking the
important parameters from a configuration file and doing all the
initialization and communication stuff.
It does NOT check for success afterwards as of now. The right approach
would be to consult /proc/bus/usb/devices (or the output of “lsusb”)
before and after execution to note any changes.
For hints about doing your own sniffing see paragraph Contribute belowBreaking News: just found this humble tool in the source code of the fine Dovado UMR
router, which they publish in compliance with the GPL. So if you want
the power of your Wireless Broadband across your local network, but
without the “fun” of setting up your own Linux router (which I did),
consider investing in such a machine.

The latest release version is 0.9.5. The archive contains the source
and a 686 binary (32 bit, VIA C7, GCC 4.2.2). I used libusb-0.1.12.
There are changes and updates to the config file more often than new
releases; most of the valuable knowledge about devices is contained in
this file. So you better use the latest version linked here.

With countless machine and distribution variants around, x86
compatibility is sometimes just not there. If you experience “floating
point errors” or the like and are not able to recompile yourself, try
one of the following drop-in replacements for the binary (all are 32
bit). And – thanks to Tobias Stoeber – we have a Debian package (for
Xandros, Etch and others); I have to admit that I never warmed to those
packaging details …

If you want to compile it for yourself, just run “compile.sh” or type on the shell:

$ gcc -l usb -o usb_modeswitch usb_modeswitch.c

That’s as easy as it gets. And it should be as portable as libusb
itself (some limitations on FreeBSD based systems are known).Take the
fresh executable “usb_modeswitch” (or the one provided with the archive)
and put it into your path (preferably “/sbin” or “/usr/sbin”).
Put “usb_modeswitch.conf” into “/etc” and edit it according to your
hardware. It’s heavily commented and should tell you what to do.
Alternatively you can use the command line interface to tell
USB_ModeSwitch the things it needs to know; try “usb_modeswitch -h” to
list the parameters. This way you can handle multiple configurations. If
any command line parameters except -W and -q are used, the default
config file is NOT read.
Important: USB_ModeSwitch – like all programs with libusb routines –
has to be run as root. Otherwise strange error messages come up …

If you’re next to certain that you have the right values for your device, followed all the hints (see Known working hardware),
and USB_ModeSwitch seems to do something run after run but to no
effect, there are most likely system issues involved. Almost all
distributions today are using “udev” as a device and hotplug manager,
and in some cases this daemon is not able to “release” the established
connection of a switched device and to see it as a freshly plugged one
(after all, this is something outside the USB specs).There are several
ways to analyse and tackle these problems:

To see what udev is doing, run udevmonitor in one console and watch
what happens if you plug the device and run USB_ModeSwitch. “lsusb”
and “dmesg” can give additional information

If you suspect timing issues, try to run USB_ModeSwitch with a defined delay after plugging

Find the device’s sysfs access. It’s in the file system under
/sys/bus/usb/devices. “dmesg” tells you what bus address it got after
plugging; should look like “1-2″ or “2-4″ or similar. Then – after
doing the switch – set it’s power level to suspend mode. For example
like this:

$ echo suspend > /sys/bus/usb/devices/1-2/power/level

Mind that the USB powersaving option must have been configured in your kernel. Thanks to mixmaxtw for this neat trick; I’ll look into adding this as a built-in option

Try the ResetUSB option with your device. This is somewhat brutal
and may also reset an internally switched device back to storage mode

Sometimes it is recommended to use the latest firmware available as
there have been issues in the past with at least one device (Icon
7.2, resolved now). In other cases devices have stopped working with
the usb-serial driver after a firmware update. So the advice is
simple: update if not working, otherwise leave alone

Very important note:
Personally, I could only test my Option Icon; the list here – as well as
all the necessary data – relies on reports from third parties (people,
that is). So don’t be surprised if you hit sudden obstacles even with
your device listed here. You have been warned.There are hitherto three
known methods for initiating the switching process:
1. sending a rarely or never used standard storage command (equivalent to those of SCSI) to the storage device
2. actively removing (rather detaching) the storage driver from the device
3. sending a special control message to the device

Option GlobeSurfer Icon (aka “Vodafone EasyBox“)
The thing that started it all, because I wanted it to work on my Linux router.
All known Option devices use the USB storage command REZERO UNIT for switching.

Option GlobeSurfer Icon 7.2
If you get hardware lockups of this thing when plugging in (flashing LEDs), update the firmware.

Option GlobeSurfer Icon 7.2 with HSO driver interface
A next generation firmware with vendor/device ID unchanging. Your “7.2
ready” device might change its behaviour after re-flashing with this
firmware; newer Option devices most likely come loaded with it. Use
the new “TargetClass” parameter to recognize already switched devices.
If you have a newer Option device not listed here there is a good chance
to get it working by using this entry and just adapting your
vendor/product ID. Note: for HSO driver questions and howtos turn to
the fine Pharscape site!

Huawei E220 (aka “Vodafone EasyBox II“, aka “T-Mobile wnw Box Micro“)
We have two options (no pun intended!) for Huawei devices: 1. detaching
of “usb-storage” 2. the special control message found by Miroslav
Bobovsky. The latter is independent of “usb-storage” and even leaves
the storage portion of the device functional. Both methods leave other
USB storage devices alone (compared to removing the storage module
completely, which works as well)

Mind that you have to run USB_ModeSwitch every time you plug your
device or cold boot with it. If you have “udev” in your distribution
it’s really not hard to automate this and just forget about it.
Note however that timing might be an issue with some of the more recent
setups. If your automatic switching is unreliable the delayed execution
of USB_ModeSwitch might help (see the special script below).
That said, since version 0.9.4 there are very few reports of timing
issues.You should have a folder named “/etc/udev” or similar. Somewhere
in there (I have a folder “rules.d”) you find some files with the
extension “.rules”. Create a new one (or edit an existing one, but by
convention not the default “50-something.rules”). I chose one named “45-hotplug.rules” since hotplugging is what USB is about after all.
In the chosen/new file add the line

SUBSYSTEM=="usb", SYSFS{idProduct}=="", SYSFS{idVendor}=="", RUN+=""

That’s basically it.From here, there are two ways to continue. If
your GSM device is recognized by a recent version of the “option” driver
you shouldn’t have to do anything but to load the module (most
certainly handled by udev automatically). Instead or if your (serial)
device is not supported by that module you can always use “usbserial”,
but it needs to be told the device IDs (plus a performance-related
option):

As for the difference between “usbserial” and “option”, here is a quote from option.c:

This driver exists because the "normal" serial driver doesn't work too well
with GSM modems. Issues:
- data loss -- one single Receive URB is not nearly enough
- nonstandard flow (Option devices) control
- controlling the baud rate doesn't make sense

Following that, I’d recommend trying the “option” driver first. In
recent kernels it recognizes several Option, Huawei and Novatel devices
(among others) out of the box. And following kernel developers mail
traffic it looks like this driver is becoming the standard for GSM
devices as more models are added. In the latest kernels the module entry
reads “USB driver for GSM and CDMA modems” (Device Drivers / USB
support / USB Serial Converter support).Devices supported by the
“option” driver that don’t change their IDs after switching might run
into problems because of the driver trying to attach before the
switching happened. In this case it might help to blacklist it and to
load it manually via the helper script after execution of
usb_modeswitch. Again, developers are working on the “option” driver to
probe for the device class before binding, so this problem might be
handled in kernel 2.6.24.
Anyway, if your device works O.K. with “usbserial”, and you are not
afraid to edit kernel sources, why not just add the vendor and product
ID (after switching of course) to the “option” driver? I
just did that with my cell phone, and now the “option” module is bound
to it automatically when plugging in. Look at the other devices included
in “option.c” and just add your IDs the same way – that’s it. Two or
three lines in most cases. Recompile, add your device to one of the udev
rules (see above) and enjoy!
For plain serial devices that keep their ID after switching a script “/sbin/mydevice_switch.sh” can be created:

If timing is an issue with your device or setup it
might help to delay the execution of USB_ModeSwitch, to allow other
drivers like “usb-storage” to finish their activation. Again, use the
helper script – called “/sbin/mydevice_switch.sh” here – and fill it
like this:

#!/bin/sh
sh -c "sleep 4; /usr/bin/usb_modeswitch" &
exit 0

Luigi Iotti reported problems on some systems (RHEL 5, CentOS 5) of
udev always waiting for background scripts to finish. Here is his
solution for a changed “/sbin/mydevice_switch.sh”:

USB_ModeSwitch comes quite handy for experimenting with your own
hardware if not supported yet. You could try this approach:Note the
device’s Vendor and Product ID from /proc/bus/usb/devices (or from the
output of “lsusb”); the assigned driver is usually “usb-storage”. Then
try spying out the USB communication to the device with the same ID
inside M$ Windoze.
I recommend this tool: “SniffUSB” (http://benoit.papillault.free.fr/usbsnoop/index.php.en).
This is the extremely short version. There is a very good case example from Mark A. Ziesemer here:Alltel UM175AL USB EVDO under Ubuntu Hardy HeronPlease post any improvements, new device information and/or bug reports to the ModeSwitchForum !
Or send me an old-fashioned e-mail (see below).