I am new to using PHP to make web requests. Previously I have only ever used node.js.
In node, our program continues to run after we send the web request. When the response comes back, then node automatically runs the callback function associated with the request.
However on PHP, I see that I can make a web request by calling curl_exec on my curl object. But how do I get the callback? What if I need to keep running code between the time when the request has been sent, and when it comes back? Is there a way to basically do a callback through some other method?
Thanks!
In PHP most functions are blocking, the program execution halts until the operation finished. This is the case with curl_exec.
You get the returned response (or a boolean indicating success) as the return value of the function. See the manual on php.net:
Returns TRUE on success or FALSE on failure. However, if the CURLOPT_RETURNTRANSFER option is set, it will return the result on success, FALSE on failure.
Related
I'm using Guzzle that I installed via composer and failing to do something relatively straightforward.
I might be misunderstanding the documentation but essentially what I'm wanting to do is run a POST request to a server and continue executing code without waiting for a response. Here's what I have :
$client = new \GuzzleHttp\Client(/*baseUrl, and auth credentials here*/);
$client->post('runtime/process-instances', [
'future'=>true,
'json'=> $data // is an array
]);
die("I'm done with the call");
Now lets say the runtime/process-instances runs for about 5mn, I will not get the die message before those 5mn are up... When instead I want it right after the message is sent to the server.
Now I don't have access to the server so I can't have the server respond before running the execution. I just need to ignore the response.
Any help is appreciated.
Things I've tried:
$client->post(/*blabla*/)->then(function ($response) {});
It is not possible in Guzzle to send a request and immediately exit. Asynchronous requests require that you wait for them to complete. If you do not, the request will not get sent.
Also note that you are using post instead of postAsync, the former is a synchronous (blocking) request. To asynchronously send a post request, use the latter. In your code example, by changing post to postAsync the process will exit before the request is complete, but the target will not receive that request.
Have you tried setting a low timeout?
Little brief about how uploading process flow in my team project.
In client side we call upload service to application server via AJAX. Application server then forward that file to File Server afterward via Curl (file server is private and can only be accessed by application server)
The situation is like this.
When files were uploading, it's already pass through the application server and reach Fileserver already. But before the data pass back to client side, user click cancel button from client.
How to check from application server, if user abort the request, then call delete to file server if it's already uploaded?
My solution
If php setting ignore_user_abort=false, I can't check if upload cancelled. So I set it to true before curl.
ini_set('ignore_user_abort', TRUE);
** Btw, ignore_user_abort=false still not terminate curl execution immediately even after script call aborted.
Set CURLOPT_NOPROGRESS to track progress if call aborted or not.
curl_setopt($ch, CURLOPT_NOPROGRESS, false);
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, 'callback_progress');
Handle progress
$cancelled = false; //cancel flag
function callback_progress($download_size, $downloaded, $upload_size, $uploaded){
//Really need this, if not connection_aborted() never be true and curl still running even if script aborted
print " "; ob_flush (); flush ();
if(connection_aborted()!= 0){
if(!$cancelled) $cancelled = true;
return 0; //to continue script, and handle later
}
}
Proceed
curl_close($ch); //close curl
ini_set('ignore_user_abort', FALSE); //set back to false
//If $cancelled if true, make delete call to file server using the file id
if($cancelled && isset($response['id'])) return $this->removeFile($response['id']);
But, it's not work. $cancelled is still false, although it's already true in callback_progress function.
Is there a better way for this? I can't find the right solution anywhere in the net for this situation.
I believe this is a case of the $cancelled variable and the call to the removeFile method not being available as at your progress function's call the part of the script you put it in will DEFINITELY have ran before the first call to callback_progress is made.
Try putting the check to see if $cancelled and request['id'] inside the callback_progress. This way the removeFile function should run when $cancelled is indeed true
I'm using the curl_multi functions with PHP. I already know that you can return the request contents from curl_exec when the CURLOPT_RETURNTRANSFER flag is on. However, how can we grab the request contents of multiple requests as strings when using curl_multi_exec?
Does it return an array when this flag is set? Nope, curl_multi_exec can only return true or false, without the option to return the contents like the normal one.
Turns out, the curl_multi_getcontent function, while somewhat inelegant, works for getting the contents as strings from each individual curl handle.
I've a PHP function which fetches a Curl request. This request sometimes take longer time than expected and hence my php function takes longer to return.
In my particular case, output of curl request is not important. So is it possible with curl just to place a request and proceed without waiting for curl_exec() to finish?
PHP does not support multi-threading, so this is not possible. You can, however, limit the amount of time cURL will execute.
$max_exe_time = 250; // time in milliseconds
curl_setopt($curl_handle, CURLOPT_TIMEOUT_MS, $max_exe_time);
You can read about this configuration option and others: http://php.net/manual/function.curl-setopt.php
Given a list of urls, I would like to check that each url:
Returns a 200 OK status code
Returns a response within X amount of time
The end goal is a system that is capable of flagging urls as potentially broken so that an administrator can review them.
The script will be written in PHP and will most likely run on a daily basis via cron.
The script will be processing approximately 1000 urls at a go.
Question has two parts:
Are there any bigtime gotchas with an operation like this, what issues have you run into?
What is the best method for checking the status of a url in PHP considering both accuracy and performance?
Use the PHP cURL extension. Unlike fopen() it can also make HTTP HEAD requests which are sufficient to check the availability of a URL and save you a ton of bandwith as you don't have to download the entire body of the page to check.
As a starting point you could use some function like this:
function is_available($url, $timeout = 30) {
$ch = curl_init(); // get cURL handle
// set cURL options
$opts = array(CURLOPT_RETURNTRANSFER => true, // do not output to browser
CURLOPT_URL => $url, // set URL
CURLOPT_NOBODY => true, // do a HEAD request only
CURLOPT_TIMEOUT => $timeout); // set timeout
curl_setopt_array($ch, $opts);
curl_exec($ch); // do it!
$retval = curl_getinfo($ch, CURLINFO_HTTP_CODE) == 200; // check if HTTP OK
curl_close($ch); // close handle
return $retval;
}
However, there's a ton of possible optimizations: You might want to re-use the cURL instance and, if checking more than one URL per host, even re-use the connection.
Oh, and this code does check strictly for HTTP response code 200. It does not follow redirects (302) -- but there also is a cURL-option for that.
Look into cURL. There's a library for PHP.
There's also an executable version of cURL so you could even write the script in bash.
I actually wrote something in PHP that does this over a database of 5k+ URLs. I used the PEAR class HTTP_Request, which has a method called getResponseCode(). I just iterate over the URLs, passing them to getResponseCode and evaluate the response.
However, it doesn't work for FTP addresses, URLs that don't begin with http or https (unconfirmed, but I believe it's the case), and sites with invalid security certificates (a 0 is not found). Also, a 0 is returned for server-not-found (there's no status code for that).
And it's probably easier than cURL as you include a few files and use a single function to get an integer code back.
fopen() supports http URI.
If you need more flexibility (such as timeout), look into the cURL extension.
Seems like it might be a job for curl.
If you're not stuck on PHP Perl's LWP might be an answer too.
You should also be aware of URLs returning 301 or 302 HTTP responses which redirect to another page. Generally this doesn't mean the link is invalid. For example, http://amazon.com returns 301 and redirects to http://www.amazon.com/.
Just returning a 200 response is not enough; many valid links will continue to return "200" after they change into porn / gambling portals when the former owner fails to renew.
Domain squatters typically ensure that every URL in their domains returns 200.
One potential problem you will undoubtably run into is when the box this script is running on looses access to the Internet... you'll get 1000 false positives.
It would probably be better for your script to keep some type of history and only report a failure after 5 days of failure.
Also, the script should be self-checking in some way (like checking a known good web site [google?]) before continuing with the standard checks.
You only need a bash script to do this. Please check my answer on a similar post here. It is a one-liner that reuses HTTP connections to dramatically improve speed, retries n times for temporary errors and follows redirects.