I want to use a simple API and i want to do it in the secure way.
It is currently using sockets and port 80. As far as I know port 80 is open and it doesn't seem such a secure connection.
As the data to send contains user and password i want to use HTTPS instead of HTTP to make it secure.
I was wondering if it is so simple as just changing this line;
$headers = "POST /api/api.php HTTP/1.0\r\n";
For this other line
$headers = "POST /api/api.php HTTPS/1.0\r\n";
And changing the port to 443
Here is the connect function:
// api connect function
function api_connect($Username, $Password, $ParameterArray)
{
// Create the URL to send the message.
// The variables are set using the input from an HTML form
$err = array();
$url = "api.text-connect.co.uk";
$headers = "POST /api/api.php HTTP/1.0\r\n";
$headers .= "Host: ".$url."\r\n";
// Create post string
// Username and Password
$poststring = "Username=".$Username."&";
$poststring .= "Password=".$Password;
// Turn the parameter array into the variables
while (list($Key, $Value)=#each($ParameterArray))
{
$poststring .= "&".$Key."=".urlencode($Value);
}
// Finish off the headers
$headers .= "Content-Length: ".strlen($poststring)."\r\n";
$headers .= "Content-Type: application/x-www-form-urlencoded\r\n";
// Open a socket
$http = fsockopen ($url, 80, $err[0], $err[1]);
if (!$http)
{
echo "Connection to ".$url.":80 failed: ".$err[0]." (".$err[1].")";
exit();
}
// Socket was open successfully, post the data.
fwrite ($http, $headers."\r\n".$poststring."\r\n");
// Read the results from the post
$result = "";
while (!feof($http))
{
$result .= fread($http, 8192);
}
// Close the connection
fclose ($http);
// Strip the headers from the result
list($resultheaders, $resultcode)=split("\r\n\r\n", $result, 2);
return $resultcode;
}
?>
Your code has a huge number of issues regardless if it's using HTTP or HTTPS - implementing an HTTP client (or server) is MUCH more complicated than simply throwing some headers across a socket then sinking the response.
What's particularly bad about this approach is that it will work some of the time - then it will fail and you won't understand why.
Start again using curl.
Doing it this way you only need to change the URL (it also implements a cookie jar, support for header injection, automatic following of redirects, routing via proxies, verification or non-verification of SSL certificates amongst other things).
I was wondering if it is so simple as
No, it isn't. It really, really isn't.
HTTPS is HTTP tunnelled over SSL. So you don't change the content of the HTTP request at all.
You do need to perform all the SSL handshaking before you do the HTTP stuff though.
SSL is crypto, it is therefore hard. Don't try reinventing this wheel. Use a library such as cURL.
curl
and set CURLOPT_SSL_VERIFYPEER = false
Related
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 :)
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.
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.
Hello
I am creating subdomains in php by the following code.
function subd($host,$port,$ownername,$passw,$request) {
$sock = fsockopen('localhost',2082);
if(!$sock) {
print('Socket error');
exit();
}
$authstr = "$ownername:$passw";
$pass = base64_encode($authstr);
$in = "GET $request\r\n";
$in .= "HTTP/1.0\r\n";
$in .= "Host:$host\r\n";
$in .= "Authorization: Basic $pass\r\n";
$in .= "\r\n";
fputs($sock, $in);
while (!feof($sock)) {
$result .= fgets ($sock,128);
}
fclose( $sock );
return $result;
}
$domain="memories.mydomain.com";
$subd="abcdef";
$request ="frontend/x3/subdomain/doadddomain.html?domain=$subd&rootdomain=$domain&dir=public_html/$subd&go=Create";
$host="ftp.mydomain.com";
$port="2083";
$ownername="ownername";
$passw="my_PASSWORD";
$result=subd($host,$port,$ownername,$passw,$request);
$show = strip_tags($result);
$d="http://$subdomainname.$domain";
echo '<META HTTP-EQUIV="Refresh" Content="0; URL='.$d.'">';
I am seeing in my cpanel sub-domain is creating but i want to redirect to my sob-domains when creation completed but instead of subdomain i am redirecting to error page which is
http://abcdef.memories.mydomain.com/cgi-sys/defaultwebpage.cgi. What is the problem behind it.Why am i redirecting to unsupported link.?
Thanks
Wow, you're writing an automated front end for an automated front end. Why don't you just create the subdomain directly in the php script, and skip messing around with cpanel?
Are you sure this should be done as a GET request? Doing things on a server via GET that have consequences is NEVER a good idea: http://thedailywtf.com/Articles/The_Spider_of_Doom.aspx
Don't use your own http client. Use curl (good) or something like file_get_contents (not as good)
Check if CPanel wants this done as a POST instead.
You pass in a port #2083, but then ignore it completely and use a hardcoded port #2082 in the function.
Your request URL has no leading /, which makes it an invalid request. You can use such paths in an HTML page, because the browser rewrites the href="" stuff by putting on the address of the page the link is in - but you're not using a browser. You're rolling your own version.
<?php
set_time_limit(0);
$errorArr = array();
if (!isset($argv[1]))
{
array_push($errorArr, "You forgot to enter a host.");
}
if ((isset($argv[1])) AND (!filter_var($argv[1], FILTER_VALIDATE_IP)))
{
array_push($errorArr, "The host you entered is not a valid IP address.");
}
if (!isset($argv[2]))
{
array_push($errorArr, "You forgot to select a port.");
}
if (!empty($errorArr))
{
echo "You have the following errors:\n";
print_r($errorArr);
die("Syntax is as follows: php {$argv[0]} host port\n");
}
$host = $argv[1];
$port = $argv[2];
echo ":::Connecting...\n";
$fh = fsockopen($host, $port);
if (!$fh)
{
die(":::Connection failed.\n:::Aborting.\n");
}
echo ":::Connected!\n:::Sending headers.\n";
$header = "PROPFIND /webdav/ HTTP/1.1\r\n";
$header .= "Host: {$host}\r\n";
$header .= "User-Agent: BitKinex/3.2.3\r\n";
$header .= "Accept: */*\r\n";
$header .= "Pragma: no-cache\r\n";
$header .= "Cache-Control: no-cache\r\n";
$header .= "Depth: 1\r\n";
$header .= "Content-Length: 220\r\n";
$header .= "Content-Type: text/xml\r\n\r\n\r\n";
if (!fwrite($fh, $header))
{
die(":::Couldn't send headers. Aborting.\n");
}
$exHeader = explode("\r\n", $header);
foreach ($exHeader as $ecHeader)
{
echo "<<<{$ecHeader}\n";
}
echo "\n:::Retrieving syntax...\n";
while(1)
{
while ($data = fgets($fh, 512))
{
echo ">>>{$data}";
flush();
}
}
?>
I'm working on a script to connect to WebDAV, upload a file, and disconnect. It connects and sends headers fine, but then it takes forever to retrieve syntax. At times, it takes several minutes, and I can't understand why. Is it a problem in my code?
And yes, I realize there's an infinite while loop there. That's done on purpose, because I haven't figured out how to know when the server is done sending information to me. So I guess that's another question, if anyone could provide insight to that.
Thanks
Your problem is because you are sending the Content-Length header with a value of 220, while not sending any content at all. The server hangs in there expecting content, but it never arrives...
And for your infinite loop thing, you don't need it at all. fgets will return false if the connection has closed. Send the Connection: close header to tell Apache to end the connection after the data has been sent. Your while loop will evaluate to false when the data has been read entirely and the connection has closed, and your loop will exit.
You might want to test it using cURL then. Try this one out: http://curl.haxx.se/mail/archive-2006-02/0000.html
That way you can see if it's server side or code side.
WebDAV can CHUG if the machine you are connecting to handles lots of traffic in general. And especially lots of web traffic. The reasons are complex, but solutions I have used in the past have primarily involved coding around the delay. Either by dumping things in a line to wait, or by pushing things to a box that isn't under heavy load but is more directly connected to the server in question and can push the files to it via different means.
This all requires access, however, and if you have control over the machines you are connecting to, you should be able to reconfigure them to give yourself priority. (which may not be an option if you are connecting to a production web server) However, I've never had to deal with this in PHP. So the problem certainly could be caused by other reasons.