Sockets are files

resource fsockopen ( string target, int port [, int error_number [, string error_string [, float timeout]]])

The simplest way to work with sockets is using them as if they were files. In fact, if you are using Unix, sockets actually are files, whereas in Windows this behaviour is just emulated.

If you read about file_get_contents() and fopen() in the Files chapter, I have some great news for you: pretty much everything you learnt there can be applied directly to sockets, which means you can fread() and fwrite() to files as you would a normal file. Take a look at the following code:

<?php
    $fp = fsockopen ("slashdot.org", 80);

    if ($fp) {
        fwrite($fp, "GET / HTTP/1.1\r\nHOST: slashdot.org\r\n\r\n");

        while (!feof($fp)) {
            print fread($fp,256);
        }

        fclose ($fp);
    } else {
        print "Fatal error\n";
    }
?>

That script performs the same function as the original fopen() script, with the exception that fsockopen() is now being used. The original script was a lot shorter, if you remember, so why bother with fsockopen() ?

Well, the fopen() remote file handler uses PHP's stream functionality to automatically connect to the server and send the HTTP request using the GET method. On the other hand, fsockopen() opens a server on the exact port we specify, then waits for us to specify what to do with it - we can, for example, send a hand-crafted HTTP request through.

As it stands, we open a socket for server slashdot.org on port 80, then, after checking the fsockopen() call has not returned false to signal failure, we write a HTTP GET request to the connection. Our HTTP request has two lines: first we send the GET request using fwrite(), asking for /, which is the root of the server. Secondly, we specify that we want to read from the host slashdot.org, which is a requirement for virtually hosted machines and HTTP 1.1.

With the HTTP request sent, we just need to wait for the response, the web page. This is done using a while loop - while there is more to be read from the file (socket), we fread() in another 256 bytes and print it out. Once we are at the end of the "file", we close the socket and end the script.

Try that script out yourself - you should see the same output as the previous script. However, now that we have full control over the HTTP connection, we can alter our request to specify that we are able to receive compressed content. Try inputting this script and running it:

<?php
    $fp = fsockopen ("slashdot.org", 80);

    if ($fp) {
        fwrite($fp, "GET / HTTP/1.1\r\nHOST: slashdot.org\r\nACCEPT-ENCODING: gzip\r\n\r\n");

        while (!feof($fp)) {
            print fread($fp,256);
        }

        fclose ($fp);
    } else {
        print "Fatal error\n";
    }
?>

Notice the fwrite() call is longer this time, because it specifies that our script is able to receive gzipped (compressed) content, so running the script this time will output seeming garbage.

If all you want to do is read in the contents of a web page, just put the URL inside a call to file_get_contents().

Author's Note: If you liked persistent database connections, you might also like persistent socket connections - the function pfsockopen() takes the same parameters as fsockopen(), but it remains open over requests.

 

Want to learn PHP 7?

Hacking with PHP has been fully updated for PHP 7, and is now available as a downloadable PDF. Get over 1200 pages of hands-on PHP learning today!

If this was helpful, please take a moment to tell others about Hacking with PHP by tweeting about it!

Next chapter: Making a simple search engine >>

Previous chapter: Sockets

Jump to:

 

Home: Table of Contents

Copyright ©2015 Paul Hudson. Follow me: @twostraws.