4

How do I make an asynchronous call to a web service using the PHP SOAP Extension?

Alive to die - Anant
  • 70,531
  • 10
  • 51
  • 98
  • Why would you want to make an asynchronous call? The only times async calls make sense to me, is on a client where you might have multiple threads going at once. But from PHP itself, generally on a server, I'm not sure I see the point. Maybe tell us what you're trying to do & we can help more. – davr Sep 24 '08 at 17:46
  • Take a look at this [post][1] It worked for me [1]: http://stackoverflow.com/a/13690590/599993 – jzafrilla Dec 04 '12 at 09:01

9 Answers9

4

My immediate answer should be: You can't.
PHP does not have threading abilities that can be used in "userland".

Now if you really want to do it, there are some ways you can go around it:

  1. Use the exec functions to spawn another process, in the background, and monitor it through the database/file system or whatever.
  2. Use the fork function to spawn another process and monitor it through the database/file system or whatever.

Setbacks of these 2 approaches is that you can make it asynchronous but if you want a callback then it's going to be very tricky and not at all trivial. Well, it ain't even gonna be a callback since you'll not be able to wait for it on the script that makes the async call. This means that you can only have some kind of monitoring scheme. I would suggest AJAX.

Gustavo Carreno
  • 9,499
  • 13
  • 45
  • 76
  • 2
    Or use curl multi: http://www.jaisenmathai.com/blog/2008/05/29/asynchronous-parallel-http-requests-using-php-multi_curl/ – Tom Jan 09 '10 at 18:59
  • 1
    You absolutely can do this in PHP without spawning another process either; you use the existing process and have it continue running after the client has disconnected. – quickshiftin Oct 03 '13 at 04:56
1

If you use curl, it has a set of 'multi' calls to allow parallel calls to multiple servers...

1

You'll need to write a SoapServer class that continues processing after the client has disconnected. This article will give you a starting point, but you'll have to wrap something similar up inside a SoapServer class.

It's going to look roughly like this (note: I've not tested this inside of SoapServer, but this gives you an idea)

class NonBlockingSoapServer extends SoapServer
{
    public function handle()
    {
        // this script can run forever
        set_time_limit(0);

        // tell the client the request has finished processing
        header('Location: index.php');  // redirect (optional)
        header('Status: 200');          // status code
        header('Connection: close');    // disconnect

        // clear ob stack 
        @ob_end_clean();

        // continue processing once client disconnects
        ignore_user_abort();

        ob_start();
        /* ------------------------------------------*/
        /* this is where regular request code goes.. */
        $result = parent::handle();
        /* end where regular request code runs..     */
        /* ------------------------------------------*/
        $iSize = ob_get_length();
        header("Content-Length: $iSize");

        // if the session needs to be closed, persist it
        // before closing the connection to avoid race
        // conditions in the case of a redirect above
        session_write_close();

        // send the response payload to the client
        @ob_end_flush();
        flush();

        /* ------------------------------------------*/
        /* code here runs after the client diconnect */
        /* YOUR ASYNC CODE HERE ......               */

        return $result;
    }
}
quickshiftin
  • 66,362
  • 10
  • 68
  • 89
1

One way is to use the select()ing method provided by CURL’s “multi” package, by extending the SoapClient class and implementing your own __doRequest.

The smallest, working example I've found can be downloaded https://github.com/halonsecurity/sp-enduser/blob/master/inc/soap.php and is used like

$client1 = new SoapClientAsync('some-systems-wsdl', $options);
$client2 = new SoapClientAsync('another-systems-wsdl', $options);
$client1->someFunction($arguments);
$client2->anotherFunction($arguments);
soap_dispatch();
$result1 = $client1->someFunction($arguments);
$result2 = $client1->anotherFunction($arguments);

as described here http://www.halon.se/blogs/making-phps-soap-client-asynchronous/

1

It may be helps, (parallel remote procedure calls): http://en.dklab.ru/lib/Dklab_SoapClient/

user570309
  • 11
  • 1
0

If you have the ability to do a command line php call in Linux, you could execute a pnctl_fork command and call the web service from the forked child process.

Devon
  • 5,786
  • 5
  • 38
  • 46
0

Do it clientside rather than server side using an AJAX type call.

Rich Bradshaw
  • 71,795
  • 44
  • 182
  • 241
0

Try the method they gave me in my question: Asynchronous PHP calls?

Community
  • 1
  • 1
Brent
  • 23,354
  • 10
  • 44
  • 49
0

I don't know why Gustavo was modded down as his is the right answer.

I use exec to run a shell script written in PHP that contacts google API. I start the script like this:

run.php param1=1 param2=2 &> ajax.txt

the last line of run is

echo 'finished'

then my ajax keeps polling 'ajax.txt' until it finds the process has finished.

Hacky, but simple (KISS)

monk.e.boy

monk.e.boy
  • 337
  • 3
  • 11