Forking a part of the php code - php

In my code I am sending a request to another page using curl_exec. I do not need the curl_exec result for the rest of the script and I do not want it to block until the curl_exec request is done and has received a response.
Any ideas if I can fork of a specific part of the script?
Or any other design ideas...?

Here's a few ideas:
Use curl_multi, and close curl at the very end of the request. You could even do this 'after shutdown'
Use worker scripts, with for example 'gearman'
Or:
You could open sockets manually, and handle stuff asynchronously using the libevent extension

Do you need the responses of the cURL requests?
First, the pcntl functions you would need to fork are generally a bad idea.
One method would be to place the cURL code in a separate script and exec() that script so it runs in the background.
$command = "php ..../wherever/your/kohana/cli/controller/is.php";
exec('php /path/to/curlscript.php > /dev/null &');
Outputting to /dev/null & allows the script to continue running in the background.
Alternatively, and probably a better solution, would be to implement a queue system such as Gearman or RabbitMQ.

Take a look at curl-multi-exec, might be what you need:

PHP doesn't support forks and threads, but you can get rid of the response by setting a response timeout:
function curl_post_async($url, $params)
{
foreach ($params as $key => &$val) {
if (is_array($val)) $val = implode(',', $val);
$post_params[] = $key.'='.urlencode($val);
}
$post_string = implode('&', $post_params);
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post_string);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_USERAGENT, 'curl');
curl_setopt($ch, CURLOPT_TIMEOUT, 1);
$result = curl_exec($ch);
curl_close($ch);
}
Taken from: How to post an asynchronous HTTP request in PHP
As the CURL documentation, you can use CURLOPT_TIMEOUT_MS since PHP 5.2.3 and CURL 7.16.2.

Related

Run url in background in php

In my application i have to send the sms to user while registration. But while inserting record in database i want to hit this url in browser.
Can any one suggest how to run this url at backgound
http://www.myurl.com/smpp/sendsms?username=XX&password=XX&to=XX&from=XX&text=Test
Well this depends on what you mean with background I'm asuming however that you mean that the user won't be redirected to that page.
If I were you I'd go with cURL if you have it installed, since the only thing you seem to want to do is make an ordinary request, and maybe, read the response. The code below is untested but should give you a hint.
$req = curl_init();
curl_setopt($req, CURLOPT_URL,"theaddress_and_params");
curl_exec($req);
public function get_url($url)
{
$cmd = "curl --max-time 60 ";
$cmd .= "'" . $url . "'";
$cmd .= " > /dev/null 2>&1 &";
exec($cmd, $output, $exit);
return $exit == 0;
}
it will call curl via cli. it will run in background.
If you did that you would be exposing usernames and passwords in the URL (or headers). Have the user login in advance and use a session variable.
Don't send this from the client side since every user would easily be able to "fake" the data by just loading your URL with some (potentially malicious) parameters. "username" and "password" are not protected at all and I'm sure your service would be down very quickly.
Instead, you could easily do this in the background (server-side) with PHPs curl functions:
http://www.php.net/manual/en/curl.examples-basic.php
$url = 'http://yoursmsgateway.com/WebSMS/SMSAPI.jsp?username='.$smsuser.'&password='.$smspwd.'&sendername='.$smssender.'&mobileno='.$number.'&message='.urlencode($message);
echo $url;
$mystring = get_data($url);
//echo "hi!";
echo $mystring;
function get_data($url) {
$ch = curl_init();
$timeout = 5;
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST,false);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER,false);
curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
You can try this code, But you have to install cUrl DLL file. Process to install CURL is given below:--
1.)open php.ini file
2.)Find this dll file---> ;extension=php_curl.dll
3.)Remove ; (semicolon)
4.)such as---> extension=php_curl.dll
5.)Save it (Ctrl+s)
you could fork a child-process with the pcntl php extension.
(library that implements this: https://github.com/kriswallsmith/spork)
Make an AJAX call as the user hits the submit button. This would cause the script at that URL to run in the background while your current PHP inserts the record in the database.
Ajax? Load that url inside a div with ajax while you save the record calling another php file with ajax.
I think that there is no such concept as multithreading (which in essence is what you are asking for), as everything in a PHP code runs incrementally, but you can get to a solution. See this and this questions and their answers.
The reason that there is no multithreading in PHP is because everything is processed in the server, and you, as a client, already receive a finished response, so "running on background" in PHP is the same as "running sequentially".

How can I close a connection to the server before the php file is done running?

E.g
<?php
//GetParameters here
//send response/end connection
//keep executing the script with the retrieved parameters.
You could do this, it just might take some tinkering. Instead of trying to close the connection on the first script, you need to process the data with a different script.
<?php
//Get Parameters
//Send output to user
//now use curl to access other script
$post = http_build_query($_POST); // you can replace this with a processed array
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://www.example.com/otherscript.php");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 0);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $post);
curl_exec($ch);
curl_close($ch);
?>
otherscript.php
<?php
header( "Connection: Close" );
// do your processing
?>
Just to explain, when curl connects it gets a connection closed header so curl quits. Meanwhile the "otherscript" is processing the data with no open connections.
I'm pretty sure using exec() may also be an option. You could simply call otherscript using php on the command line passing the variables as cmd line arguments. Something like this should work for you if you are running linux:
exec("nohup php -f otherscript.php -- '$arg1' '$arg2' < /dev/null &");
Now otherscript.php is running in the background under a different process id

How to make a cUrl request without receiving the response?

Normally I Post data when I initiate cURL. And I wait for the response, parse it, etc...
I want to simply post data, and not wait for any response.
In other words, can I send data to a Url, via cURL, and close my connection immediately? (not waiting for any response, or even to see if the url exists)
It's not a normal thing to ask, but I'm asking anyway.
Here's what I have so far:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $MyUrl);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_to_send);
curl_exec($ch);
curl_close($ch);
I believe the only way to not actually receive the whole response from the remote server is by using CURLOPT_WRITEFUNCTION. For example:
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $MyUrl);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_to_send);
curl_setopt($ch, CURLOPT_WRITEFUNCTION, 'do_nothing');
curl_exec($ch);
curl_close($ch);
function do_nothing($curl, $input) {
return 0; // aborts transfer with an error
}
Important notes
Be aware that this will generate a warning, as the transfer will be aborted.
Make sure that you do not set the value of CURLOPT_RETURNTRANSFER, as this will interfere with the write callback.
You could do this through the curl_multi_* functions that are designed to execute multiple simultaneous requests - just fire off one request and don't bother asking for the response.
Not sure what the implications are in terms of what will happen if the script exits and curl is still running.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $MyUrl);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data_to_send);
$mh = curl_multi_init();
curl_multi_add_handle($mh,$ch);
$running = 'idc';
curl_multi_exec($mh,$running); // asynchronous
// don't bother with the usual cleanup
Not sure if this helps, but via command-line I suppose you could use the '--max-time' option - "Maximum time in seconds that you allow the whole operation to take."
I had to do something quick and dirty and didn't want to have to re-program code or wait for a response, so found the --max-time option in the curl manual
curl --max-time 1 URL

Call to new HttpRequest fails

I am trying to get a PHP script working. The purpose of the script is to call out to a web service. I've reduced the script down to it's simpliest components and it is still failing. Here it is:
<?php
print "Hello";
$request = new HttpRequest('http://www.pivotaltracker.com/services/v3/source_commits', HttpRequest::METH_POST);
print "Done";
?>
The output is:
D:\svn\svndb\hooks>"c:\Program Files\PHP\php.exe" -f test.php
Hello
D:\svn\svndb\hooks>
As you can see, the script fails when trying to instantiate an instance of HttpRequest. However, no exception is thrown.
I am not a PHP program... I'm just trying to get this feature working. I suspect I have no loaded an extension library that I need... but I can't figure out which one that would be, if indeed that is the problem.
I am running on Windows 2003. I am running PHP 5.3.3.
I did run phpinfo() but am hesitant to post the results here since it is so large. Is there a section of the phpinfo() output that would be helpful to provide?
Put a error_reporting(E_ALL); in front and see what happens.
My bet is that the HTTPRequest class doesn't exist. The HTTP extension is a PECL package that needs to be installed separately.
Thank you everyone for your answers. They were all spot on. I thought I'd summnarize what I did in the end in case it helps someone else.
The problem was indeed that I had not installed the http PECL extension. Unfortunately, I am on windows and there was no distriubtion of this extension and I didn't want to install the microsoft tools on this box to be able to compile the source. So, I went with the suggestion listed above and implemented it using curl.
The script I was working on was to integration svn to http://www.pivotaltracker.com using the excellent php script found at http://phpjack.com/content/pivotal-tracker-and-subversion. I modified that script as follows (in case someone else is in a similar spot):
$request = new HttpRequest('http://www.pivotaltracker.com/services/v3/source_commits', HttpRequest::METH_POST);
$headers = array(
'X-TrackerToken' => $token,
'Content-type' => 'application/xml'
);
$request->setHeaders($headers);
$request->setBody("<source_commit><message>$message</message><author>$author</author><commit_id>$rev</commit_id></source_commit>");
$request->send();
became
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HTTPHEADER, array("Content-Type: application/xml","X-TrackerToken: $token"));
curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
curl_setopt($ch, CURLOPT_POST, 1);
$result = curl_exec ($ch);
curl_close ($ch);
print $result;
Thanks again for all the excellent and timely advise.
Error reporting by error_reporting( E_ALL );
Enable display errors ini_set('display_errors', 1);
Better to change these settings from php.ini.
If it's not working look at apache logs (error.log)
You could use cURL for that simple purpose:
<?php
$url = "http://www.pivotaltracker.com/services/v3/source_commits";
$ch = curl_init();
// set the target url
curl_setopt($ch, CURLOPT_URL, $url);
// howmany parameter to post
curl_setopt($ch, CURLOPT_POST, 1);
// parameters
curl_setopt($ch, CURLOPT_POSTFIELDS, "someParameter=someValue");
$result = curl_exec ($ch);
curl_close ($ch);
print $result;
?>
Or use fsockopen() to connect to a server and fwrite to send a raw http post request.

curl halts script execution

my script uses curl to upload images to smugsmug site via smugsmug api.
i loop through a folder and upload every image in there. but after 3-4 uploads, curl_exec would fail, stopped everything and prevent other images from uploading.
$upload_array = array(
"method" => "smugmug.images.upload",
"SessionID" => $session_id,
"AlbumID" => $alb_id,
"FileName" => zerofill($n, 3) . ".jpg",
"Data" => base64_encode($data),
"ByteCount" => strlen($data),
"MD5Sum" => $data_md5);
$ch = curl_init();
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);
curl_setopt($ch, CURLOPT_POSTFIELDS, $upload_array);
curl_setopt(
$ch, CURLOPT_URL,
"https://upload.smugmug.com/services/api/rest/1.2.2/");
$upload_result = curl_exec($ch); //fails here
curl_close($ch);
updated:
so i added logging into my script. when it does fail, the logging stops after fwrite($fh, "begin curl\n");
fwrite($fh, "begin curl\n");
$upload_result = curl_exec($ch);
fwrite($fh, "curl executed\n");
fwrite($fh, "curl info: ".print_r(curl_getinfo($ch,true))."\n");
fwrite($fh, "xml dump: $upload_result \n");
fwrite($fh, "curl error: ".curl_error($ch)."\n");
i also
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 60*60);
Not sure what the issue is... What is in the response when it fails? What do the system and apache logs say?
Now if i were you i wouldnt use curl_init() and curl_close() in the loop. instead i would init before the loop, and close after the loop - then within the loop itsef i would use curl_set_opt to set the url and differing parameters and just call curl_exec(). It may even be its a matter of all these handles exceeding some kind of system limit or something. If you need/want to use multiple connections you could use curl_multi or write some management functions/class to manage multiple handles.
We may need more info before we can help, but it sounds like it could be a timeout issue.
Turn on error reporting or check your error logs to see if anything is being raised.
Try setting a long cURL timeout with CURLOPT_TIMEOUT
Also check that your script timeout is sufficient or increase with set_time_limit()
1- Force Curl to tell you a bit more about what it does
curl_setopt($ch, CURLOPT_VERBOSE, true);
curl_setopt($ch, CURLOPT_HEADER, true);
2- If you are not in safe mode, make sure PHP displays errors by putting this at the beginning of your script:
<?php
ini_set('display_errors', '1');
error_reporting(E_ALL);
3- You can also try to run your script in CLI mode.
4- Finally, still if you are not in safe mode, you can try to directly run the curl binary using exec().
<?php
$curl_str = "curl -k -o /my/path/curl_output.log -d 'var1=".$value1."&var2=".$value2."& etc...' https://upload.smugmug.com/services/api/rest/1.2.2/";
$r = exec($curl_str);
CURL includes the 'multi' (for multiple-resources) options for when one is dealing with multiple high-latency requests (such as uploading images).
See:
http://www.php.net/manual/en/function.curl-multi-exec.php
and the entire library of 'multi' functions described here:
http://php.net/manual/en/book.curl.php
For a complete example of the multiple resource section of the library, see:
http://www.developertutorials.com/blog/php/parallel-web-scraping-in-php-curl-multi-functions-375/
You could try whether outputting curl_error() directly works:
$upload_result = curl_exec($ch); //fails here
$error = curl_error($ch);
if ($error) echo "CURL Error: $error";
curl_close($ch);
If that doesn't help, check your phpinfo(); to see whether error reporting is turned off globally (look for the display_errors setting).

Categories