php libcurl alternative - php

Are there any alternatives to using curl on hosts that have curl disabled?

To fetch content via HTTP, first, you can try with file_get_contents ; your host might not have disabled the http:// stream :
$str = file_get_contents('http://www.google.fr');
Bit this might be disabled (see allow_url_fopen) ; and sometimes is...
If it's disabled, you can try using fsockopen ; the example given in the manual says this (quoting) :
$fp = fsockopen("www.example.com", 80, $errno, $errstr, 30);
if (!$fp) {
echo "$errstr ($errno)<br />\n";
} else {
$out = "GET / HTTP/1.1\r\n";
$out .= "Host: www.example.com\r\n";
$out .= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
while (!feof($fp)) {
echo fgets($fp, 128);
}
fclose($fp);
}
Considering it's quite low-level, though (you are working diretly with a socket, and HTTP Protocol is not that simple), using a library that uses it will make life easier for you.
For instance, you can take a look at snoopy ; here is an example.

http://www.phpclasses.org is full of these "alternatives", you can try this one: http://www.phpclasses.org/browse/package/3588.html

You can write a plain curl server script with PHP and place it on curl-enabled hosting, and when you need curl - you make client calls to it when needed from curl-less machine, and it will return data you need. Could be a strange solution, but was helpful once.

All the answers in this thread present valid workarounds, but there is one thing you should keep in mind. You host has, for whatever reason, deemed that making HTTP requests from your web server via PHP code is a "bad thing", and have therefore disabled (or not enabled) the curl extension. There's a really good chance if you find a workaround and they notice it that they'll block your request some other way. Unless there's political reasons forcing you into using this particular host, seriously consider moving your app/page elsewhere if it need to make http requests.

Related

Send HTTP request from PHP without waiting for response?

I want to have an HTTP GET request sent from PHP. Example:
http://tracker.example.com?product_number=5230&price=123.52
The idea is to do server-side web-analytics: Instead of sending tracking
information from JavaScript to a server, the server sends tracking
information directly to another server.
Requirements:
The request should take as little time as possible, in order to not
noticeably delay processing of the PHP page.
The response from the tracker.example.com does not need to be
checked. As examples, some possible responses from
tracker.example.com:
200: That's fine, but no need to check that.
404: Bad luck, but - again - no need to check that.
301: Although a redirect would be appropriate, it would delay
processing of the PHP page, so don't do that.
In short: All responses can be discarded.
Ideas for solutions:
In a now deleted answer, someone suggested calling command line
curl from PHP in a shell process. This seems like a good idea,
only that I don't know if forking a lot of shell processes under
heavy load is a wise thing to do.
I found php-ga, a package for doing server-side Google
Analytics from PHP. On the project's page, it is
mentioned: "Can be configured to [...] use non-blocking requests."
So far I haven't found the time to investigate what method php-ga
uses internally, but this method could be it!
In a nutshell: What is the best solution to do generic server-side
tracking/analytics from PHP.
Unfortunately PHP by definition is blocking. While this holds true for the majority of functions and operations you will normally be handling, the current scenario is different.
The process which I like to call HTTP-Ping, requires that you only touch a specific URI, forcing the specific server to boot-strap it's internal logic. Some functions allow you to achieve something very similar to this HTTP-ping, by not waiting for a response.
Take note that the process of pinging an url, is a two step process:
Resolve the DNS
Making the request
While making the request should be rather fast once the DNS is resolved and the connection is made, there aren't many ways of making the DNS resolve faster.
Some ways of doing an http-ping are:
cURL, by setting CONNECTION_TIMEOUT to a low value
fsockopen by closing immediately after writing
stream_socket_client (same as fsockopen) and also adding STREAM_CLIENT_ASYNC_CONNECT
While both cURL and fsockopen are both blocking while the DNS is being resolved. I have noticed that fsockopen is significantly faster, even in worst case scenarios.
stream_socket_client on the other hand should fix the problem regarding DNS resolving and should be the optimal solution in this scenario, but I have not managed to get it to work.
One final solution is to start another thread/process that does this for you. Making a system call for this should work, but also forking the current process should do that also. Unfortunately both are not really safe in applications where you can't control the environment on which PHP is running.
System calls are more often than not blocked and pcntl is not enabled by default.
I would call tracker.example.com this way:
get_headers('http://tracker.example.com?product_number=5230&price=123.52');
and in the tracker script:
ob_end_clean();
ignore_user_abort(true);
ob_start();
header("Connection: close");
header("Content-Length: " . ob_get_length());
ob_end_flush();
flush();
// from here the response has been sent. you can now wait as long as you want and do some tracking stuff
sleep(5); //wait 5 seconds
do_some_stuff();
exit;
I implemented function for fast GET request to url without waiting for response:
function fast_request($url)
{
$parts=parse_url($url);
$fp = fsockopen($parts['host'],isset($parts['port'])?$parts['port']:80,$errno, $errstr, 30);
$out = "GET ".$parts['path']." HTTP/1.1\r\n";
$out.= "Host: ".$parts['host']."\r\n";
$out.= "Content-Length: 0"."\r\n";
$out.= "Connection: Close\r\n\r\n";
fwrite($fp, $out);
fclose($fp);
}
We were using fsockopen and fwrite combo, then it up and stopped working one day. Or it was kind of intermittent. After a little research and testing, and if you have fopen wrappers enabled, I ended up using file_get_contents and stream_context_create functions with a timeout that is set to 100th of second. The timeout parameter can receive floating values (https://www.php.net/manual/en/context.http.php). I wrapped it in a try...catch block so it would fail silently. It works beautifully for our purposes. You can do logging stuff in the catch if needed. The timeout is the key if you don't want the function to block runtime.
function fetchWithoutResponseURL( $url )
{
$context = stream_context_create([
"http" => [
"method"=>"GET",
"timeout" => .01
]
]
);
try {
file_get_contents($url, 0, $context);
}catch( Exception $e ){
// Fail silently
}
}
For those of you working with wordrpess as a backend -
it is as simple as:
wp_remote_get( $url, array(blocking=>false) );
Came here whilst researching a similar problem. If you have a database connection handy, one other possibility is to quickly stuff the request details into a table, and then have a seperate cron-based process that periodically scans that table for new records to process, and makes the tracking request, freeing up your web application from having to make the HTTP request itself.
You can use shell_exec, and command line curl.
For an example, see this question
You can actually do this using CURL directly.
I have both implemented it using a very short timeout (CURLOPT_TIMEOUT_MS) and/or using curl_multi_exec.
Be advised: eventually i quit this method because not every request was correctly made. This could have been caused by my own server though i haven't been able to rule out the option of curl failing.
I needed to do something similar, just ping a url and discard all responses. I used the proc_open command which lets you end the process right away using proc_close. I'm assuming you have lynx installed on your server:
<?php
function ping($url) {
$proc = proc_open("lynx $url",[],$pipes);
proc_close($proc);
}
?>
<?php
// Create a stream
$opts = array(
'http'=>array(
'method'=>"GET",
'header'=>"Accept-language: en"
)
);
$context = stream_context_create($opts);
// Open the file using the HTTP headers set above
$file = file_get_contents('http://tracker.example.com?product_number=5230&price=123.52', false, $context);
?>

PHP Async GET request works on one server, but doesn't on the other

Please see the edits at the bottom for additional information!
I have two servers. Both should be able to call each other with a GET request.
To make the request (it's more firing an event than makeing a request actually) I am using this code:
function URLCallAsync($url, $params, $type='POST')
{
foreach ($params as $key => &$val) {
if (is_array($val)) $val = implode(',', $val);
$post_params[] = $key.'='.urlencode($val);
}
$post_string = implode('&', $post_params);
$parts=parse_url($url);
$fp = fsockopen($parts['host'],
isset($parts['port'])?$parts['port']:80,
$errno, $errstr, 30);
// Data goes in the path for a GET request
if('GET' == $type) $parts['path'] .= '?'.$post_string;
$out = "$type ".$parts['path']." HTTP/1.1\r\n";
$out.= "Host: ".$parts['host']."\r\n";
$out.= "Content-Type: application/x-www-form-urlencoded\r\n";
$out.= "Content-Length: ".strlen($post_string)."\r\n";
$out.= "Connection: Close\r\n\r\n";
// Data goes in the request body for a POST request
if ('POST' == $type && isset($post_string)) $out.= $post_string;
fwrite($fp, $out);
fclose($fp);
}
I feed the function with the exact same data (but the url) on both servers (I copied the calling file to test it!!) but it only works in one direction!
I write the calls to that function in a log file so I can investigate if something is going wrong.
Server A -> Server B, works exactly as it should, the logfile at server A contains the correct url
Server B -> Server A, only prints the correct information in the logfile of server B, but Server A never receives the request.
What could be the reason for something like this?
edit:
Could it be the differnt kinds of server?
Server A is nginx, Server B is apache.
Server A also has a '~' symbol in it's url, maybe thats the problem?
The parameters of the get request are encoded with php's "urlencode" maybe that creates problems?
I tried around a bit, but the problem is still that the request isn't coming trough to Server A. But from a browser it works perfectly somehow (assuming I enter the correct URL with the parameters).
edit2:
If I exchange "URLCallAsync" with "file_get_contents" it works like it should. But the problem is that file_get_contents is blocking!
So it can only be the function itself. But strangely it works in the opposite direction :(
edit3:
The function "URLCallAsync" runs trough without error, notice or anything else.
It just isn't received by the other server.
What exactly is file_get_contents doing so different???
I got it working.
After a lot of fiddling with wireshark I found that file_get_contents is even simpler than my async function!
It simply omits the Content-Length field completly! It just provides "GET ..." and "Host".
It also uses HTTP/1.0 instead of 1.1, but that didn't change anything.
So the solution is: Also posting the Content-Length header (which had the value 0, since i used GET) will somehow make the server reject the request. I don't know for sure if it was the server that rejected the request, or something else, like a firewall that maybe detected a "malformed" request, but at least the problem is solved.
So next time you send requests, don't provide the Content-Length header if you don't need it :)

Not receiving a response from Paypal IPN Sandbox

I'm putting a paypal checkout onto my website but am falling down with the listener.
For those of you who are unfamiliar with the Paypal IPN system, basically Paypal sends your script with a message about the transaction, which you send back with a couple of bits added. If Paypal receives the correct reply, it'll reply with 'VERIFIED', and if not it'll say 'INVALID'.
I've succeeded with the first bit. My code is able to receive the info from paypal, add on the extras and post it back. However, I get no response from the Sandbox saying either 'VERIFIED' or 'INVALID'. I've pretty much copied my code from the paypal website so I was hoping this was going to be fairly straightforward, so if you could take a minute to look at my code, perhaps some new eyes could pick out where I've gone wrong.
Here's the code. Nothing special, it literally just gets the info, adjusts it, passes it back and reads the response (which it either isn't getting or doesn't realise it's getting)
<?php
$debug=true;
//Put together postback info
$postback = 'cmd=_notify-validate';
foreach($_POST as $key =>$value){
$postback .= "&$key=$value";
}
// build the header string to post back to PayPal system to validate
$header = "POST /cgi-bin/webscr HTTP/1.1\r\n";
$header .= "Host: www.sandbox.paypal.com\r\n";
$header .= "Content-Type: application/x-www-form-urlencoded\r\n";
$header .= "Content-Length: " . strlen($postback) . "\r\n\r\n";
$fp = fsockopen ('www.sandbox.paypal.com', 80, $errno, $errstr, 30);//open the connection
if(!$fp){ //no conn
die();
}
//post data back
fputs($fp, $header . $postback);
while(!feof($fp)){
$res=fgets ($fp, 1024);
if((strcmp($res, "VERIFIED")) == 0){ //verified!
if($debug){
$filename = 'debug/debug5_verified.txt'; //create a file telling me we're verified
$filehandle=fopen($filename, 'w');
fwrite($filehandle,'VERIFIED!');
fclose($filehandle);
}
}
}
?>
Thanks in advance!
Switch over to using the HTTPS url, I'm not sure when but recently all of my test scripts started failing on the plain HTTP version. They look to be migrating over.
I'm using the same paypal sample code you are:
$fp = fsockopen ('ssl://www.sandbox.paypal.com', 443, $errno, $errstr, 30);
or
$fp = fsockopen ('ssl://www.paypal.com', 443, $errno, $errstr, 30);
So I think I found a solution. Turns out it wasn't having trouble with connecting to ssl://sandbox...., it was actually retrieving the answer. The code was getting hung up on the
while(!feof($fp)){
$res=fgets($fp,1024);
}
bit. All I did was replace it with:
$res=stream_get_contents($fp, 1024);
and it worked first time! Now I can get on with my life. Thanks again for all the help on this one.
Perhaps the original code was missing:
$header .= "Connection: close\r\n\r\n";
Note that the Paypal sample code uses HTTP/1.0 so does not have that line. And HTTP/1.1 is fine but might need the line.
On another issue, Sandbox may no longer support port 80. I am getting a 302 redirect to https://www.sandbox.paypal.com.
I've noticed that the URL you are posting to is a little different than below, could this be it?
this is from the IPN Testing help page:
Check that your are posting your response to the correct URL, which is https://www.sandbox.paypal.com/cgi-bin/webscr or https://www.paypal.com/cgi-bin/webscr, depending on whether you are testing in the Sandbox or you are live, respectively.
Verify that your response contains exactly the same IPN variables and values in the same order, preceded with cmd=_notify-validate.
Ensure that you are encoding your response string and are using the same character encoding as the original message.
EDIT: Sorry I also wanted to mention that the port for HTTP and HTTPS are different, 80 as opposed to 443. I'm not too familiar with Paypal API but could look into it as I see you are using 80.
PayPal test server moved to:
$fp = fsockopen('ssl://ipnpb.paypal.com', 443, $errno, $errstr, 30);
check up php version tls socket. it should be tls 1.2 to get the response from sandbox account. upgrade the php version to 5.5 to get tls 1.2 socket.
paypal has disabled the service of sslv3 and changed to tls 1.2.
if you need to get the response,php version must require tls 1.2, in order to get tls 1.2 php can be upgraded to 5.5 or more.
visit the link.

Are there any other options for rest clients besides CURL?

Are there alternatives to CURL in PHP that will allow for a client to connect o a REST architecture server ?
PUT, DELETE, file upload are some of the things that need to work.
You can write your own library. It's even possible to do it completely in PHP, using fsockopen and friends. For example:
function httpget($host, $uri) {
$msg = 'GET '.$uri." HTTP/1.1\r\n".
'Host: '.$host."\r\n".
"Connection: close\r\n\r\n";
$fh = fsockopen($host, 80);
fwrite($fh, $msg);
$result = '';
while(!feof($fh)) {
$result .= fgets($fh);
}
fclose($fh);
return $result;
}
I recommend Zend_Http_Client (from Zend) or HTTP_Request2 (from PEAR). They both provide a well-designed object model for making HTTP requests.
In my personal experience, I've found the Zend version to be a little more mature (mostly in dealing with edge cases).

How to call a WebSocket programmatically (using PHP)?

I have a situation where I need to update one browser window based on input from the other. Right now I'm using WebSockets and it's working great.
Now I want to send data to the WebSocket using PHP instead of the browser (so instead of ws://, use PHP code). In other words, I want to simulate the WebSocket.send() call using PHP instead of JavaScript.
I have the following code which doesn't seem to work (the onmessage is not being called):
if (
function_exists('socket_create') AND
$sock = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP) AND
$sock_data = socket_connect($sock, "127.0.0.1", 12345)
) {
$msg = "hello world";
$sock_data = socket_set_option($sock, SOL_SOCKET, SO_BROADCAST, 1); //Set
$sock_data = socket_write($sock, $msg, strlen($msg)); //Send data
socket_close($sock); //Close socket
}
Here's how it's done:
http://permalink.gmane.org/gmane.comp.lang.javascript.nodejs/18088
$host = 'localhost'; //where is the websocket server
$port = 9000;
$local = "http://localhost/"; //url where this script run
$data = 'hello world!'; //data to be send
$head = "GET / HTTP/1.1"."\r\n".
"Upgrade: WebSocket"."\r\n".
"Connection: Upgrade"."\r\n".
"Origin: $local"."\r\n".
"Host: $host"."\r\n".
"Content-Length: ".strlen($data)."\r\n"."\r\n";
//WebSocket handshake
$sock = fsockopen($host, $port, $errno, $errstr, 2);
fwrite($sock, $head ) or die('error:'.$errno.':'.$errstr);
$headers = fread($sock, 2000);
fwrite($sock, "\x00$data\xff" ) or die('error:'.$errno.':'.$errstr);
$wsdata = fread($sock, 2000); //receives the data included in the websocket package "\x00DATA\xff"
fclose($sock);
In order to send data to the socket, you need to use fsockopen to open the connection to the socket at specified port. If the connection is successfully, all you need to do is use fwrite
However, you are going to be sending the data to the WebSocket server. The server will treat you as a client, and since you are not providing HTTP headers it expects for successful authentication - your connection will be refused.
Since you didn't say who is supposed to receive the message you are trying to send (all users or a specific user or something entirely different), without knowing what your goal is - it's hard to explain any further what you should do.
There is a lot more to WebSockets than just sending the raw data to a TCP socket.
Ok, to start, you're using a UDP socket, where WebSockets use TCP. WebSockets is an entire protocol for communication, similar to HTTP, so you need to follow that protocol, there is a handshake step that you need to perform first and headers you need to add to all communication. It's not difficult, but I'm not going to go into detail here.
You have two options from here, implement the WebSockets protocol in php, or use a pre-built library like this one: http://code.google.com/p/phpwebsocket/
I'm not being rude, or mean, but in the future, try a quick Google search. That library I linked was found after googling "PHP WebSockets".
The most important part is that the message needs to be sent on the existing socket, meaning you cant call socket_connect, fsockopen, or any other function within PHP that will attempt an unsolicited connection to the client. This isn't a websocket thing - that's a fundamental concept in network programing.
On phpwebsocket it would be somethin like:
$msg = "hello world";
$phpwebsocket->send($user->socket, $msg);
where '$phpwebsocket' is the PHP WebSocket object, $user->socket is a connected user who connected priory using with a javascript WebSocket(), and send() is a method within the WebSocket object that will properly encode the message into a frame (or should as it will soon be required).
However, if for any reason you want to connect to the websocket server using websockets from PHP, you'll want to check out https://github.com/nicokaiser/php-websocket. The server in the link wont be of any importance if your happy with your current solution, but the package also contains a PHP Websocket client class which is what you would need.
Checkout ratchet
You can use something like telnet with popen/proc_open to communicate with the socket server.

Categories