14

I have a two websites in php and python. When a user sends a request to the server I need php/python to send an HTTP POST request to a remote server. I want to reply to the user immediately without waiting for a response from the remote server.

Is it possible to continue running a php/python script after sending a response to the user. In that case I'll first reply to the user and only then send the HTTP POST request to the remote server.

Is it possible to create a non-blocking HTTP client in php/python without handling the response at all?

A solution that will have the same logic in php and python is preferable for me.

Thanks

pablo
  • 141
  • 1
  • 1
  • 3
  • [A **real** non-blocking HTTP client written in PHP](https://github.com/rdlowrey/Artax). –  Dec 04 '13 at 05:53
  • @rdlowrey AMP is asynchronous but that doesn't mean it is non-blocking. Eventually it does block and wait for the response. – PHP Guru Mar 18 '22 at 16:37

6 Answers6

6

In PHP you can close the connection by sending this request (this is HTTP related and works also in python, although I don't know the proper syntax to use):

// Send the response to the client
header('Connection: Close');
// Do the background job: just don't output anything!

Addendum: I forgot to mention you probably have to set the "Context-Length". Also, check out this comment for tips and a real test case.

Example:

<?php    
ob_end_clean();
header('Connection: close');

ob_start();

echo 'Your stuff goes here...';

header('Content-Length: ' . ob_get_length());

ob_end_flush();
flush();

// Now we are in background mode
sleep(10);
echo 'This text should not be visible';    
?>
ntd
  • 7,372
  • 1
  • 27
  • 44
  • how will it work in a framework? For example in MVC framework? Do I have to do it as part of the framework itself as the last step or can I just use it in one of the controllers? – pablo Oct 12 '09 at 17:15
  • I don't know your use case. If you need to perform a _new_ operation in background, I'd enclose the whole framework in the `ob_start()`...`ob_end_flush()` pair. But here I'm guessing. MVC is an empty word for me... the better candidate would be the controller though. – ntd Oct 12 '09 at 18:01
  • This isn't working for me... in a test script, after I put the header('Connection: Close'), I put a sleep(5). When I hit it in the browser, its still sleeping. Did I miss something? – ContextSwitch Jun 24 '14 at 20:11
  • @ContextSwitch: you should read the comment linked in the answer. Anyway I provided an example. – ntd Jul 23 '14 at 22:05
  • @ntd Thanks, i had missed the linked comment – ContextSwitch Jul 24 '14 at 01:17
  • In the tests that I did the Connection: close header is optional as the browser already knows to close the connection from the Content-Length header. – PHP Guru Mar 19 '22 at 18:25
2

You can spawn another process to handle the POST to the other server. In PHP you would spawn the process and "disconnect" so you don't wait for the response.

exec("nohup /path/to/script/post_content.php > /dev/null 2>&1 &");

You can then you curl to perform the post. If you want to pass parameters to the PHP script, you can use the getopt() function to read them. Not sure if you would do something similar in Python.

Brent Baisley
  • 12,641
  • 2
  • 26
  • 39
1

What you need to do is have the PHP script execute another script that does the server call and then sends the user the request.

Anthony
  • 36,459
  • 25
  • 97
  • 163
  • Right, you would do it either over exec() or cURL. You aren't starting a thread, you are just initiating another script that's running independently of your one that deals with the user response. – Anthony Oct 12 '09 at 17:15
  • So if exec() is too slow, just do it via cURL. Make a post request to the other script with whatever data from the user request the secondary script needs to send to the remote server. Set the secondary script to respond to your main script with "Got it, thanks" and have it keep going after that. – Anthony Oct 12 '09 at 17:18
0

You have to set a middle man. So in your own server you would have:

  • A web form;
  • A submit handler ( php or python script that handles the form submission );
    • Your handler creates a new file and fill it up with the submission data. You can, for instance, format the data as JSON;
    • So your handler has a single job, save the submitted data in a file and respond the user, nothing else. This should be fast.
  • Create a filesystem event driven cron ( not a time driven cron ). See this and this questions (for a windows and an ubuntu servers respectively).
    • Set your cron to execute a php or python script which will then re-post the data to a remote server.
Francisco Luz
  • 2,775
  • 2
  • 25
  • 35
-1

You have to use fsockopen. And don't listen to the result

<?php

$fp = fsockopen('example.com', 80);

$vars = array(
    'hello' => 'world'
);
$content = http_build_query($vars);

fwrite($fp, "POST /reposter.php HTTP/1.1\r\n");
fwrite($fp, "Host: example.com\r\n");
fwrite($fp, "Content-Type: application/x-www-form-urlencoded\r\n");
fwrite($fp, "Content-Length: ".strlen($content)."\r\n");
fwrite($fp, "Connection: close\r\n");
fwrite($fp, "\r\n");

fwrite($fp, $content);
Mangirdas Skripka
  • 1,647
  • 1
  • 15
  • 14
  • There are multiple problems with this. I will start with the main problem. If I don't listen for the result before PHP exits, the connection is closed before it is able to complete and the POST is not successful. The solution: Do whatever needs to be done after you finish calling fwrite, then listen for the result before exiting PHP. The other problems with this are that 1) This is not secure. This should connect over TLS and 2) you need to check the return value of fwrite when writing to a network. See the fwrite_stream example at https://www.php.net/manual/en/function.fwrite.php – PHP Guru Mar 18 '22 at 16:25
-6

Hookah is designed to solve your problem.

Dustin
  • 89,080
  • 21
  • 111
  • 133