Using PHP with Node.js in Windows
Tags: php, node, javascript, webdev
Published: 2022-08-24 16:41:24

{% embed https://codehouse.digfish.org/using-php-with-node-js-in-windows/ %}
PHP and Node.js are two coding standards made for Web purposes. Node.js is not a language by itself and is a new implementation of Javascript and a different filosophy in programming.
PHP adopted some features of Node like the package manager NPM on Composer and the assincronicity make the bulk of some frameworks like [Laravel](https://laravel.com/ "Laravel")
. Node.js with the help of libraries can do almost the same complete languages like Python. The new [Electron.JS](https://www.electronjs.org/ "Electron.JS") for desktop applications uses Node behind the scenes. It's the base for some applications like VS Code or the Spotify desktop client. PHP is not for the desktop, and it remains closed in the same purposes since it was created in 1995 by [Rasmus Lerdorf](https://www.siliconrepublic.com/enterprise/rasmus-lerdorf-php-7).
<!--more-->

Using the node standalone server provided by the http module and the FastCGI PHP client it's possible to serve PHP files from within node. Let me show how.

PHP 5.4 introduced the new standalone builtin web server in PHP, its possible to make the node server proxify the requests and responses of PHP, but it's not the way we are doing the things here.

The [FastCGI](https://www.mit.edu/~yandros/doc/specs/fcgi-spec.html) was introduced to add flexibility and standardization to what was a plethora of ways that common binary runtimes like bash could serve webpages. Before PHP arrived, languages like Perl were used to generate dynamic web content. 

For some web servers that do not come with access through a shared library, PHP-CGI (on Linux, PHP-FPM, from FastCGI PHP Manager) is the way to do it. The front web server receives a request for a PHP script and makes a request to the PHP CGI client, including details like web script name, the string query, and an eventual request body. The CGI client answers with HTML or other format outputted from PHP.

Nginx and Lighttpd use this way to server PHP web content, NodeJS can also interface with FastCGI through the node [php-fpm](https://www.npmjs.com/package/php-fpm) module.

The code is:
```
const phpFpm = require ('php-fpm');
const php = phpFpm({
    host: '127.0.0.1',
    port: 9123,
    documentRoot: __dirname + '\\www',
});
```
The PHP CGI client must be already listening at the port 9123 and was started with the args: `php-cgi -b 127.0.0.1:9123`. On Linux it's `php-fpm` and the args should be the same, but I haven't tried it.

Here my document root is under a subdir in the project root. I do this because I'm using configuration files in the root and conf dirs. Web visitors doesn't may have access to these.

Name the file `server.js`, launch the node web server with `node server.js`, in the root dir at `www/` you can have the following PHP code:
```php
<?php
echo "<H1>Hello, today's date is " . date("Y-m-d") . " and more!</H1>";
```

Name this file `index.php`, save it to the `www`, and if you navigate to [http://localhost:3000/index.php](http://localhost:3000/index.php) you should see something like:

![PHP CGI Output in Node](https://codehouse.digfish.org/wp-content/uploads/2022/08/phpfpmoutput-300x60.png)

The complete code of `server.js` is below:

```javascript
const http = require ('http');
const fs = require ('fs');
const phpFpm = require ('php-fpm');

const php = phpFpm({
    host: '127.0.0.1',
    port: 9123,
    documentRoot: __dirname + '\\www',
    debug: false
});
 

const server = http.createServer((req, res) => {
    let url = req.url;
    let method = req.method;
    console.log('Serving request: ' + method + ' ' + url );
    if (url == '/') { 
        readAndServe('index.html', res);
    } else if (url.endsWith('.php')) {
        php(req,res);
    } else {
        readAndServe(url, res);
    } 
}).listen(3000, '127.0.0.1',function() {
    let {address, port} = server.address();
    console.log('Server started at '+ address+ ':'+ port);
});

// Helper function 
function readAndServe(path, res) {
    fs.readFile('www/' + path, function (err, data) {
        if (err) {
            console.error(err);
            res.writeHead(404, { 'Content-Type': 'text/plain' });
            data = '404 Not Found\n';
       }
        res.end(data);
    });
}
```