13

I just tried this code:

<?php
set_time_limit(0);

$address = '176.9.117.136';
$port = 9000;

$sock = socket_create(AF_INET, SOCK_STREAM, 0);
socket_bind($sock, $address, $port) or die('Could not bind to address');

while(1)
{
    socket_listen($sock);
    $client = socket_accept($sock);

    $input = socket_read($client, 1024);
    echo $input;

    $output = 'URL: http://ip-of-my-server:9000/
HTTP/1.1 200 OK
Date: Tue, 10 Jul 2012 16:58:23 GMT
Server: TestServer/1.0.0 (PHPServ)
Last-Modified: Fri, 06 Jul 2012 14:29:58 GMT
ETag: "13c008e-1b9-4c42a193de580"
Accept-Ranges: bytes
Content-Length: 441
Vary: Accept-Encoding
Content-Type: text/html

';
    socket_write($client, $output);

    socket_close($client);
}

socket_close($sock);
?>

But there is a problem. Instead of using the content of $output as the headers, Apache returns its own headers...

I don't know why because I execute the script via this command: php webserv.php.

However it practically works, because when I load the page http://ip-of-my-server:9000/ from my browser, it shows me the headers sent by the client on the server, and returns the content of $output to the client (my browser).

I want to create my own webserver only in PHP if it's possible. I just want to know how to run it without Apache, so I can manage my own HTTP headers.

rodneyrehm
  • 13,442
  • 1
  • 40
  • 56
Yoone
  • 547
  • 3
  • 8
  • 22
  • 2
    Just in case you were unaware, PHP5.4 ships with a built-in web server so you don't have to do this sort of thing ... –  Jul 10 '12 at 17:30
  • 1
    This seems like reinventing the wheel. I assure you, there are many many wheels out there. – Wug Jul 10 '12 at 17:30
  • 4
    rdlowrey: I know that, yes. Wug: It's just to learn... I would never use it as a production webserver. I just want to create my own to know how it works from A to Z. – Yoone Jul 10 '12 at 17:32
  • Do you have an instance of apache running on the same machine at all? You might want to try disable it and try again... – Lix Jul 10 '12 at 17:33
  • There is Nanoweb, and PEARs HTTP_Server for reference. – mario Jul 10 '12 at 17:34
  • possible duplicate of [PHP web server in PHP?](http://stackoverflow.com/questions/6131679/php-web-server-in-php) – mario Jul 10 '12 at 17:35
  • Yes I did some research and found Nanoweb. I want to do something similar (with less features of course). – Yoone Jul 10 '12 at 17:35
  • @Yoone, building a web server using PHP will not teach you the A to Z. For that, dump PHP and do it using C. – Pacerier Nov 19 '13 at 13:46
  • @Pacerier: I asked this question about a year ago and, since that, I also did it in C# and C :) (a basic implementation of course). I was just messing around with sockets in PHP and it actually served me well in some of my recent projects! – Yoone Nov 19 '13 at 18:21

3 Answers3

18

Is there a reason to implement an HTTP server in PHP (of all things)? There's no threading, etc. It would be a pain… (unless this is some sort of academic thing…)

PHP 5.4 ships with a built-in webserver. Maybe that is what you're looking for…


Update:

While I understand your motivation to learn this sort of stuff, I believe you're on the wrong track trying this sort of stuff with PHP. PHP is not really designed for long running processes (like a server would be), it is not equipped for parallel processing (threads). Even multi-processing would require PCNTL, specifically pcntl_fork() and limit your educational walkabout to a Unix based system (which may not be a problem, though).

If your goal is to understand how servers deal with concurrency, I suggest playing with a language designed for that (Erlang, Go, Scala, …). Or play with a language that at least sort of emulates parallel processing (Python, Ruby, … [sort of, because of their GILs]).

If your goal is to understand HTTP (and let me tell you HTTP is a beast, if you're going past HTTP/1.0 and want to do it right), fiddling with PHP may be fine, if it's the only language you're firm in. If so, have a look at the example code (chat server) in this (sadly German) article on Socket Servers in PHP to get the basic socket stuff running an concentrate on the actual HTTP.


Update 2:

To answer your question regarding the headers… I have no clue how apache would fit into the scenario described in your question. But I see you're using line-breaks to delimit headers and a double line-break to delimit headers from body. Unless you've saved your php file using \r\n as the default line-break (windows-style), you're header-part is malformed and would thus be recognized as the body. Depending on the http client (user agent, may it be your browser, or curl, or whatever) this may be treated with "insert some default headers". Replace your line-breaks with \r\n and try again.

If your server is reachable from the internet, try some header test tools to verify your HTTP is sound. If it is localhost-only, see what curl -I http://ip-of-my-server:9000 spits out.

rodneyrehm
  • 13,442
  • 1
  • 40
  • 56
  • 1
    Yes this is a sort of academic thing, but it's only for me. I just want to learn and go further in the use of PHP. – Yoone Jul 10 '12 at 17:34
  • 1
    +1 - I've got no idea who downvoted but he has to be an idiot to downvote. Having to create a HTTP server isn't just a "next,next,next" task. Specially if you're doing it in PHP. – tftd Jul 10 '12 at 17:34
  • 1
    @tftd I know that, but I'll repeat myself, it is only to learn how to do it. I'll never use it for a production website... – Yoone Jul 10 '12 at 17:37
  • Learning the how it works is great, thats what makes you a good programmer, learning when to use something you learned deeply thats wisdom and you only get that with experience. Don't be afraid to try out stuff, but use common sense. – Mathieu Dumoulin Jul 10 '12 at 17:40
  • @MathieuDumoulin I've been on it for 10h today, I tried a lot of things, a lot of different approachs, and this one seems to be the best (the code I provided in my first message). But there is this problem with Apache I really can't solve... – Yoone Jul 10 '12 at 17:43
  • Updated the answer to tell a little more about why PHP may not be the best environment for playing with socket servers – rodneyrehm Jul 10 '12 at 17:44
  • Comment for the "after update" message: my question is not really about the sockets. I found a lot of tutorials and pieces of code, this is not the real problem (I even looked at Nanoweb's source code). But I have this problem with Apache, and this is why I asked this question. And I will do it in PHP anyway, even if it's not adapted for a webserver, that's not the problem. As I said twice, I don't do this for a production website. This is only for myself. It's like "oh we can do it! let's do it!" – Yoone Jul 10 '12 at 17:45
  • Gotta agree with @rodneyrehm - although I think building a webserver is a great way to learn more about a language, I don't think it's the best project to attempt using PHP. – Mansfield Jul 10 '12 at 17:47
  • updated the answer again, to elaborate on `\r\n` vs. `\n` in header delimitation. maybe that was your quirk. if it didn't help, I'm out of ideas… – rodneyrehm Jul 10 '12 at 17:51
  • @rodneyrehm Thank you, I'll try replacing the `\n` by `\r\n`. Edit: well, it doesn't solve the problem. – Yoone Jul 10 '12 at 17:54
  • @rodneyrehm To answer your last update: I tried with your tool, and the headers are the ones I set. But from another tool like that, I see Apache headers (see http://bit.ly/OuTDfF). My server is online, the IP adress is 176.9.117.136. And you can try from your browser, you can see the headers in the content of the page. – Yoone Jul 10 '12 at 18:20
  • @rodneyrehm Sorry to notify you again, it now seems to work! Is was, like you said, some default headers which were inserted. I'll give you a +1 and accept your answer because you're the one who helped me the most. Thanks! – Yoone Jul 10 '12 at 18:48
  • It is what "Connectify" has done to share user's files via web page. (my thought) – Oki Erie Rinaldi Dec 29 '14 at 06:18
  • Umm... PHP now supports multi threading... due to this amazing extension `pthreads` built by @JoeWatkins https://github.com/krakjoe/pthreads/ and there is a example too to build a server here using `pthreads` https://github.com/krakjoe/pthreads/blob/master/examples/SocketServer.php – Ikari Mar 03 '16 at 16:50
  • In 2021, there is even an entire non blocking I/O framework based on PHP, called [AMPHP](https://amphp.org/). – Code4R7 Jul 22 '21 at 13:51
  • And for enthusiasts like myself there is a complete tutorial on [how to build a multithreaded webserver from scratch](https://doc.rust-lang.org/book/ch20-00-final-project-a-web-server.html) in Rust. – Code4R7 Sep 18 '22 at 13:53
2

I think what you are meaning by web-server in this instance is simply some socket communication between a server and a client or sorts. My experience with PHP and sockets has been with flash proxy clients.

This involves embedding a 1x1px flash pixel somewhere on your page and using it as a bridge between the flash pixel, Javascript and PHP Socket Server. (socket communication is really a breeze with ActionScript once you know how it works). This method is also the only way you'll get maximum browser compatibility (even the more advanced websocket frameworks like socket.io use this flash pixel method as a fallback).

Another option is of course WebSockets similar to the ones used on this very site for the live-refresh feature. There is even a tag dedicated to it here on Stack Overflow.

If you want to play around creating a socket server with PHP, your client would have to be something other than just your browser.

Hope this steers you in the right direction...

Community
  • 1
  • 1
Lix
  • 47,311
  • 12
  • 103
  • 131
  • I'm not sure I understand everything, but how can I create a "full" webserver, with a client which is only a web browser? – Yoone Jul 10 '12 at 17:57
  • If that is specifically what you are looking for then I have to agree with what was said by other about re-inventing the wheel... If you simply want to look into socket communication with PHP then maybe you should start with something smaller than an HTTP server... – Lix Jul 10 '12 at 18:00
  • 1
    No, I really want to create an HTTP server in PHP. I don't want to "only" learn about sockets. – Yoone Jul 10 '12 at 18:04
2

The code you tried originally was very close but just required a few minor changes:

<?php
set_time_limit(0);

$address = '127.0.0.1';
$port = 80;

$sock = socket_create(AF_INET, SOCK_STREAM, 0);
socket_bind($sock, $address, $port) or die('Could not bind to address');

echo "\n Listening On port $port For Connection... \n\n";

while(1)
{
    socket_listen($sock);
    $client = socket_accept($sock);

    $input = socket_read($client, 1024);

    $incoming = array();
    $incoming = explode("\r\n", $input);

    $fetchArray = array();
    $fetchArray = explode(" ", $incoming[0]);

    $file = $fetchArray[1];
    if($file == "/"){ 

        $file = "index.html"; 

    } else {

        $filearray = array();
        $filearray = explode("/", $file);
        $file = $filearray[1];
    }

echo $fetchArray[0] . " Request " . $file . "\n"; 

$output = "";
$Header = "HTTP/1.1 200 OK \r\n" .
"Date: Fri, 31 Dec 1999 23:59:59 GMT \r\n" .
"Content-Type: text/html \r\n\r\n";

$Content = file_get_contents($file);
$output = $Header . $Content;

    socket_write($client,$output,strlen($output));
    socket_close($client);
}

This code here will now will revive the header of the request packet to find the requested file and then it will go to the local directory for that file. As it stands this only works with html so it doesn't support images but it would do fine as a really light weight web-server. also it currently defaults to index.html, so just save this, put some html files in the same directory and point a browser at it.

cheers hope this helped!

StingRay
  • 21
  • 1