├── LICENSE ├── README.md ├── lib ├── cli-wrapper.js └── nodephp.js ├── package.json └── php.js /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2010-2011 David Coallier 2 | All rights reserved. 3 | 4 | Redistribution and use in source and binary forms, with or without modification, 5 | are permitted provided that the following conditions are met: 6 | 7 | * Redistributions of source code must retain the above copyright notice, 8 | this list of conditions and the following disclaimer. 9 | 10 | * Redistributions in binary form must reproduce the above copyright notice, 11 | this list of conditions and the following disclaimer in the documentation 12 | and/or other materials provided with the distribution. 13 | 14 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 15 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 16 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 17 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR 18 | ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 19 | (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 20 | LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 21 | ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 | (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 23 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Inline PHP Server Running on Node.js 2 | ==================================== 3 | 4 | Be worried, be very worried. The name **NodePHP** takes its name from the fact that we are effectively 5 | turning a nice Node.js server into a FastCGI interface that interacts with PHP-FPM. 6 | 7 | This is omega-alpha-super-beta-proof-of-concept but it already runs a few simple scripts. Mostly done 8 | for my talks on **Node.js for PHP Developers** this turns out to be quite an interesting project that 9 | we are most likely be going to use with [Orchestra](http://orchestra.io) when we decide to release our 10 | **Inline PHP server** that allows people to run PHP without Apache, Nginx or any webserver. 11 | 12 | Yes this goes against all ideas and concepts of Node.js but the idea is to be able to create a web-server 13 | directly from any working directory to allow developers to get going even faster than it was before. No 14 | need to create vhosts or server blocks ore modify your /etc/hosts anymore. 15 | 16 | Synopsis 17 | -------- 18 | This node.js module is made for the sole purpose of my conference talk but also to allow developers to 19 | get started with PHP even faster than the usual. After installing this node-module, developers need to make 20 | sure they have PHP-FPM running somewhere on their system. If it is, they will be able to go to any of their 21 | web-directory (that the FPM user has access to) and simply type `node php` and from there they will see a 22 | nice little output that looks like this: 23 | 24 | bash$~ PHP Server is now running on port 9001 25 | Incoming Request: GET /test.php 26 | --> Request Response Status Code: "200" 27 | 28 | This is going to be running in the browser allowing you to develop and test your applications faster. Hopefully 29 | you will end up **forking** the project and helping out because I do not have enough time to do all I would want to 30 | do with this thing. 31 | 32 | 33 | What? 34 | ----- 35 | It allows you to go into a directory, type "node-php" and have a running webserver that serves PHP. Happy?... 36 | 37 | 38 | Installing 39 | ---------- 40 | Well this is a bit tricky, there are a few things you will need in order to get this thang running: 41 | 42 | - You need a running PHP-FPM server. 43 | - You need to have Node.js installed with NPM 44 | - Install **node-fastcgi-parser** ( https://github.com/billywhizz/node-fastcgi-parser ) 45 | - Then you `git clone git://github.com/davidcoallier/node-php.git`, then you `git submodule init`, then you `git submodule update`, and `npm install` 46 | 47 | For this beta version, we assume that you are running FPM off `localhost` on port `9000`. If you are running 48 | through a **socket** you may want to make your own script that looks like this: 49 | 50 | var php = require('nodephp'); 51 | php.nodephp({ 52 | fcgi: { 53 | port: '/tmp/php-fpm.sock', 54 | host: null, 55 | }, 56 | server: { 57 | port: 9998 58 | } 59 | }); 60 | 61 | Please note that the sock connection has not been tested yet. All that has been tested is connecting to a different 62 | FastCGI port and starting the server on a different port like such: 63 | 64 | var php = require('nodephp'); 65 | php.nodephp({ 66 | fcgi: { 67 | port: 9001, 68 | host: 'localhost', 69 | }, 70 | server: { 71 | port: 9111 72 | } 73 | }); 74 | 75 | 76 | Serving Static Files 77 | -------------------- 78 | You will realise rapidly enough that only running this is quite useless as it does not serve static files and such. This is why the **node-php** 79 | code has the abiliyt to define **blocks** — albeit simple blocks. They are defined in the second argument of the nodephp call: 80 | 81 | var php = require('nodephp'); 82 | php.nodephp({ 83 | fcgi: { 84 | port: 9001, 85 | host: 'localhost', 86 | }, 87 | server: { 88 | port: 9111 89 | } 90 | }, { 91 | "\.(js|css|png|jpg|jpeg|gif|txt|less)$": php.NODEPHP_TYPE_STATIC, 92 | "\.php$": php.NODEPHP_TYPE_FCGI, 93 | "index": "index.php" 94 | }); 95 | 96 | Where the following are: 97 | 98 | NODEPHP_TYPE_STATIC: Static files that do not need to go through the fastcgi handler (`fastcgi_pass`) 99 | NODEPHP_TYPE_FCGI: Files you do send through the FCGI handler. 100 | 101 | If you want more simple using the default `localhost:9000` for the FCGI handler: 102 | 103 | var php = require('nodephp'); 104 | php.nodephp({}, { 105 | "\.(js|css|png|jpg|jpeg|gif|txt|less)$": php.NODEPHP_TYPE_STATIC, 106 | "\.php$": php.NODEPHP_TYPE_FCGI, 107 | "index": "index.php" 108 | }); 109 | 110 | Hopefully this helps. 111 | 112 | 113 | Issues & Todos 114 | ------------------ 115 | There are a few very important issues right now: 116 | 117 | - There is no POST handling. I'm not that far in the FCGI specs yet — need to find how to send data (post data) 118 | - There is no **base** url. If you include ../../../../poop it will try to load it and most likely will fail. 119 | - If you try to load a file that the PHP-FPM worker does not have access to, it will fail silently and you will swear. A lot. By silently I mean, it will give you a 404 even though the files do exist. 120 | 121 | 122 | Disclaimer 123 | ---------- 124 | This is an ugly prototype and if you run this in production you are most likely mentally challenged (Not that it's a bad thing..) but 125 | I take no responsibility for what you do with this. Moreover, this goes against everything Node.js stands for. So realise that. 126 | 127 | 128 | License 129 | ------- 130 | Released under the New BSD License. 131 | 132 | Copyright (c) 2011 David Coallier 133 | -------------------------------------------------------------------------------- /lib/cli-wrapper.js: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | var path = require("path"), 4 | args = process.argv.slice(1) 5 | 6 | var arg, base; 7 | do arg = args.shift(); 8 | while ( arg !== __filename && 9 | (base = path.basename(arg)) !== "node-php" && 10 | base !== "php" && 11 | base !== "php.js" 12 | ) 13 | 14 | require("./php").run(args) 15 | -------------------------------------------------------------------------------- /lib/nodephp.js: -------------------------------------------------------------------------------- 1 | var url = require('url'); 2 | var fs = require('fs'); 3 | var path = require("path"); 4 | var http = require("http"); 5 | var net = require("net"); 6 | var sys = require("sys"); 7 | var fastcgi = require("fastcgi"); 8 | 9 | var NODEPHP_STATIC = 'static'; 10 | var NODEPHP_FCGI = 'fcgi'; 11 | 12 | var params; 13 | 14 | var FCGI_RESPONDER = fastcgi.constants.role.FCGI_RESPONDER; 15 | var FCGI_BEGIN = fastcgi.constants.record.FCGI_BEGIN; 16 | var FCGI_STDIN = fastcgi.constants.record.FCGI_STDIN; 17 | var FCGI_STDOUT = fastcgi.constants.record.FCGI_STDOUT; 18 | var FCGI_PARAMS = fastcgi.constants.record.FCGI_PARAMS; 19 | var FCGI_END = fastcgi.constants.record.FCGI_END; 20 | 21 | /** 22 | * Make headers for FPM 23 | * 24 | * Some headers have to be modified to fit the FPM 25 | * handler and some others don't. For instance, the Content-Type 26 | * header, when received, has to be made upper-case and the 27 | * hyphen has to be made into an underscore. However, the Accept 28 | * header has to be made uppercase, hyphens turned into underscores 29 | * and the string "HTTP_" has to be appended to the header. 30 | * 31 | * @param array headers An array of existing user headers from Node.js 32 | * @param array params An array of pre-built headers set in serveFpm 33 | * 34 | * @return array An array of complete headers. 35 | */ 36 | function makeHeaders(headers, params) { 37 | if (headers.length <= 0) { 38 | return params; 39 | } 40 | 41 | for (prop in headers) { 42 | head = headers[prop]; 43 | prop = prop.replace(/-/, '_').toUpperCase(); 44 | if (prop.indexOf('CONTENT_TYPE') < 0) { 45 | // Quick hack for PHP, might be more or less headers. 46 | prop = 'HTTP_' + prop; 47 | } 48 | 49 | params[params.length] = [prop, head] 50 | } 51 | 52 | return params; 53 | }; 54 | 55 | /** 56 | * Interact with FPM 57 | * 58 | * This function is used to interact with the FastCGI protocol 59 | * using net.Stream and the fastcgi module. 60 | * 61 | * We pass the request, the response, some params and some options 62 | * that we then use to serve the response to our client. 63 | * 64 | * @param object Request The HTTP Request object. 65 | * @param object Response The HTTP Response object to use. 66 | * @param array Params A list of parameters to pass to FCGI 67 | * @param array options A list of options like the port of the fpm server. 68 | * 69 | * @return void 70 | */ 71 | function server(request, response, params, options) { 72 | var connection = new net.Stream(); 73 | connection.setNoDelay(true); 74 | 75 | var writer = null; 76 | var parser = null; 77 | 78 | var header = { 79 | "version": fastcgi.constants.version, 80 | "type": FCGI_BEGIN, 81 | "recordId": 0, 82 | "contentLength": 0, 83 | "paddingLength": 0 84 | }; 85 | var begin = { 86 | "role": FCGI_RESPONDER, 87 | "flags": 0 88 | }; 89 | 90 | function sendRequest (connection) { 91 | header.type = FCGI_BEGIN; 92 | header.contentLength = 8; 93 | writer.writeHeader(header); 94 | writer.writeBegin(begin); 95 | connection.write(writer.tobuffer()); 96 | 97 | header.type = FCGI_PARAMS; 98 | header.contentLength = fastcgi.getParamLength(params); 99 | writer.writeHeader(header); 100 | writer.writeParams(params); 101 | connection.write(writer.tobuffer()); 102 | 103 | header.type = FCGI_STDOUT; 104 | writer.writeHeader(header); 105 | connection.write(writer.tobuffer()); 106 | 107 | connection.end(); 108 | }; 109 | 110 | connection.ondata = function (buffer, start, end) { 111 | parser.execute(buffer, start, end); 112 | }; 113 | 114 | connection.addListener("connect", function() { 115 | writer = new fastcgi.writer(); 116 | parser = new fastcgi.parser(); 117 | 118 | body=""; 119 | 120 | parser.onRecord = function(record) { 121 | if (record.header.type == FCGI_STDOUT) { 122 | body = record.body; 123 | 124 | parts = body.split("\r\n\r\n"); 125 | 126 | headers = parts[0]; 127 | headerParts = headers.split("\r\n"); 128 | 129 | body = parts[1]; 130 | 131 | var responseStatus = 200; 132 | 133 | headers = []; 134 | try { 135 | for(i in headerParts) { 136 | header = headerParts[i].split(': '); 137 | if (header[0].indexOf('Status') >= 0) { 138 | responseStatus = header[1].substr(0, 3); 139 | continue; 140 | } 141 | 142 | headers.push([header[0], header[1]]); 143 | } 144 | } catch (err) { 145 | //console.log(err); 146 | } 147 | 148 | headers.push(['X-Server' , 'Node.js-' + process.version]); 149 | response.writeHead(responseStatus, headers); 150 | response.end(body); 151 | 152 | console.log(' --> Request Response Status Code: "' + responseStatus + '"'); 153 | } 154 | }; 155 | 156 | parser.onHeader = function(header) { 157 | body = ''; 158 | }; 159 | 160 | parser.onError = function(err) { 161 | //console.log(err); 162 | }; 163 | 164 | sendRequest(connection); 165 | }); 166 | 167 | connection.addListener("close", function() { 168 | connection.end(); 169 | }); 170 | 171 | connection.addListener("error", function(err) { 172 | sys.puts(sys.inspect(err.stack)); 173 | connection.end(); 174 | }); 175 | 176 | connection.connect(options.fcgi.port, options.fcgi.host); 177 | } 178 | 179 | /** 180 | * Serve a static file. 181 | * 182 | * This function is used to serve static files back to the users. A static 183 | * file is determined by looking at the map of static files we have in the 184 | * function and the file is then read, served with it's associated 185 | * content-type and then the response object is used to say: "We're done." Next. 186 | * 187 | * @param string file The request file to parse. 188 | * @param string path The path to the file to parse. 189 | * @param object response The HTTP Response object. 190 | * @param object request The HTTP Request object. 191 | * 192 | * @return void 193 | */ 194 | function serveStatic(file, path, response, request) { 195 | // List taken from djangode 196 | // @link https://github.com/simonw/djangode/blob/master/djangode.js 197 | var types = { 198 | ".3gp" : "video/3gpp", 199 | ".a" : "application/octet-stream", 200 | ".ai" : "application/postscript", 201 | ".aif" : "audio/x-aiff", 202 | ".aiff" : "audio/x-aiff", 203 | ".asc" : "application/pgp-signature", 204 | ".asf" : "video/x-ms-asf", 205 | ".asm" : "text/x-asm", 206 | ".asx" : "video/x-ms-asf", 207 | ".atom" : "application/atom+xml", 208 | ".au" : "audio/basic", 209 | ".avi" : "video/x-msvideo", 210 | ".bat" : "application/x-msdownload", 211 | ".bin" : "application/octet-stream", 212 | ".bmp" : "image/bmp", 213 | ".bz2" : "application/x-bzip2", 214 | ".c" : "text/x-c", 215 | ".cab" : "application/vnd.ms-cab-compressed", 216 | ".cc" : "text/x-c", 217 | ".chm" : "application/vnd.ms-htmlhelp", 218 | ".class" : "application/octet-stream", 219 | ".com" : "application/x-msdownload", 220 | ".conf" : "text/plain", 221 | ".cpp" : "text/x-c", 222 | ".crt" : "application/x-x509-ca-cert", 223 | ".css" : "text/css", 224 | ".csv" : "text/csv", 225 | ".cxx" : "text/x-c", 226 | ".deb" : "application/x-debian-package", 227 | ".der" : "application/x-x509-ca-cert", 228 | ".diff" : "text/x-diff", 229 | ".djv" : "image/vnd.djvu", 230 | ".djvu" : "image/vnd.djvu", 231 | ".dll" : "application/x-msdownload", 232 | ".dmg" : "application/octet-stream", 233 | ".doc" : "application/msword", 234 | ".dot" : "application/msword", 235 | ".dtd" : "application/xml-dtd", 236 | ".dvi" : "application/x-dvi", 237 | ".ear" : "application/java-archive", 238 | ".eml" : "message/rfc822", 239 | ".eps" : "application/postscript", 240 | ".exe" : "application/x-msdownload", 241 | ".f" : "text/x-fortran", 242 | ".f77" : "text/x-fortran", 243 | ".f90" : "text/x-fortran", 244 | ".flv" : "video/x-flv", 245 | ".for" : "text/x-fortran", 246 | ".gem" : "application/octet-stream", 247 | ".gemspec": "text/x-script.ruby", 248 | ".gif" : "image/gif", 249 | ".gz" : "application/x-gzip", 250 | ".h" : "text/x-c", 251 | ".hh" : "text/x-c", 252 | ".htm" : "text/html", 253 | ".html" : "text/html", 254 | ".ico" : "image/vnd.microsoft.icon", 255 | ".ics" : "text/calendar", 256 | ".ifb" : "text/calendar", 257 | ".iso" : "application/octet-stream", 258 | ".jar" : "application/java-archive", 259 | ".java" : "text/x-java-source", 260 | ".jnlp" : "application/x-java-jnlp-file", 261 | ".jpeg" : "image/jpeg", 262 | ".jpg" : "image/jpeg", 263 | ".js" : "application/javascript", 264 | ".json" : "application/json", 265 | ".log" : "text/plain", 266 | ".m3u" : "audio/x-mpegurl", 267 | ".m4v" : "video/mp4", 268 | ".man" : "text/troff", 269 | ".mathml" : "application/mathml+xml", 270 | ".mbox" : "application/mbox", 271 | ".mdoc" : "text/troff", 272 | ".me" : "text/troff", 273 | ".mid" : "audio/midi", 274 | ".midi" : "audio/midi", 275 | ".mime" : "message/rfc822", 276 | ".mml" : "application/mathml+xml", 277 | ".mng" : "video/x-mng", 278 | ".mov" : "video/quicktime", 279 | ".mp3" : "audio/mpeg", 280 | ".mp4" : "video/mp4", 281 | ".mp4v" : "video/mp4", 282 | ".mpeg" : "video/mpeg", 283 | ".mpg" : "video/mpeg", 284 | ".ms" : "text/troff", 285 | ".msi" : "application/x-msdownload", 286 | ".odp" : "application/vnd.oasis.opendocument.presentation", 287 | ".ods" : "application/vnd.oasis.opendocument.spreadsheet", 288 | ".odt" : "application/vnd.oasis.opendocument.text", 289 | ".ogg" : "application/ogg", 290 | ".p" : "text/x-pascal", 291 | ".pas" : "text/x-pascal", 292 | ".pbm" : "image/x-portable-bitmap", 293 | ".pdf" : "application/pdf", 294 | ".pem" : "application/x-x509-ca-cert", 295 | ".pgm" : "image/x-portable-graymap", 296 | ".pgp" : "application/pgp-encrypted", 297 | ".pkg" : "application/octet-stream", 298 | ".pl" : "text/x-script.perl", 299 | ".pm" : "text/x-script.perl-module", 300 | ".png" : "image/png", 301 | ".pnm" : "image/x-portable-anymap", 302 | ".ppm" : "image/x-portable-pixmap", 303 | ".pps" : "application/vnd.ms-powerpoint", 304 | ".ppt" : "application/vnd.ms-powerpoint", 305 | ".ps" : "application/postscript", 306 | ".psd" : "image/vnd.adobe.photoshop", 307 | ".py" : "text/x-script.python", 308 | ".qt" : "video/quicktime", 309 | ".ra" : "audio/x-pn-realaudio", 310 | ".rake" : "text/x-script.ruby", 311 | ".ram" : "audio/x-pn-realaudio", 312 | ".rar" : "application/x-rar-compressed", 313 | ".rb" : "text/x-script.ruby", 314 | ".rdf" : "application/rdf+xml", 315 | ".roff" : "text/troff", 316 | ".rpm" : "application/x-redhat-package-manager", 317 | ".rss" : "application/rss+xml", 318 | ".rtf" : "application/rtf", 319 | ".ru" : "text/x-script.ruby", 320 | ".s" : "text/x-asm", 321 | ".sgm" : "text/sgml", 322 | ".sgml" : "text/sgml", 323 | ".sh" : "application/x-sh", 324 | ".sig" : "application/pgp-signature", 325 | ".snd" : "audio/basic", 326 | ".so" : "application/octet-stream", 327 | ".svg" : "image/svg+xml", 328 | ".svgz" : "image/svg+xml", 329 | ".swf" : "application/x-shockwave-flash", 330 | ".t" : "text/troff", 331 | ".tar" : "application/x-tar", 332 | ".tbz" : "application/x-bzip-compressed-tar", 333 | ".tcl" : "application/x-tcl", 334 | ".tex" : "application/x-tex", 335 | ".texi" : "application/x-texinfo", 336 | ".texinfo" : "application/x-texinfo", 337 | ".text" : "text/plain", 338 | ".tif" : "image/tiff", 339 | ".tiff" : "image/tiff", 340 | ".torrent" : "application/x-bittorrent", 341 | ".tr" : "text/troff", 342 | ".txt" : "text/plain", 343 | ".vcf" : "text/x-vcard", 344 | ".vcs" : "text/x-vcalendar", 345 | ".vrml" : "model/vrml", 346 | ".war" : "application/java-archive", 347 | ".wav" : "audio/x-wav", 348 | ".weba" : "audio/webm", 349 | ".webm" : "video/webm", 350 | ".wma" : "audio/x-ms-wma", 351 | ".wmv" : "video/x-ms-wmv", 352 | ".wmx" : "video/x-ms-wmx", 353 | ".wrl" : "model/vrml", 354 | ".wsdl" : "application/wsdl+xml", 355 | ".xbm" : "image/x-xbitmap", 356 | ".xhtml" : "application/xhtml+xml", 357 | ".xls" : "application/vnd.ms-excel", 358 | ".xml" : "application/xml", 359 | ".xpm" : "image/x-xpixmap", 360 | ".xsl" : "application/xml", 361 | ".xslt" : "application/xslt+xml", 362 | ".yaml" : "text/yaml", 363 | ".yml" : "text/yaml", 364 | ".zip" : "application/zip" 365 | }; 366 | 367 | console.log('Incoming Request: ' + request.method + ' ' + request.url); 368 | try { 369 | response.writeHead(200, {'Content-Type': types[file.substr(file.lastIndexOf('.'), file.length)]}); 370 | response.write(fs.readFileSync(path + file, 'utf8')); 371 | response.end(); 372 | } catch (Exception) { 373 | response.writeHead(400, {'Content-Type': types[file.substr(file.lastIndexOf('.'), file.length)]}); 374 | response.write('
432 | * {
433 | * fcgi: {port: 9000, host: localhost},
434 | * server: {port: 9001}
435 | * }
436 | *
437 | *
438 | * The block parameter is used to define the rules of which types to serve.
439 | *
440 | * {
441 | * "\.(js|css)$": 'static',
442 | * }
443 | *
444 | */
445 | function createServer(opts, block) {
446 |
447 | // Let's mix those options.
448 | var options = Object.create({
449 | fcgi: {
450 | port: 9000,
451 | host: 'localhost', // This can be a socket.
452 | },
453 | server: {
454 | port: 9001,
455 | }
456 | });
457 | options.extend(opts);
458 |
459 | http.createServer(function(request, response) {
460 | /**
461 | * Here's a list of things to change:
462 | *
463 | * - Retrieve teh correct script invoked by parsing the request.url
464 | * and analysing the filename passed.
465 | *
466 | * - Rewrite rules?
467 | * - Location blocks?
468 | * - Get the headers and insert them correctly in Params.
469 | */
470 |
471 | // We simulate that the index page is is index.php if the requested
472 | // script was "/".
473 | var script_file = request.url == '/' ? '/index.php' : url.parse(request.url).pathname;
474 | var script_name = script_file.substr(1, script_file.length);
475 |
476 | // We only pass `pwd` as the second argument an we can run a server
477 | // with the directory index of the current directory. Handy.
478 | var __script_dir__ = process.cwd();
479 |
480 | // For now.
481 | var pathname = url.parse(request.url).pathname;
482 | var extension = pathname.substr(pathname.lastIndexOf('.'), pathname.length);
483 |
484 | for (rule in block) {
485 | if (rule == 'index') { continue; }
486 | if (pathname.match(rule)) {
487 | if (block[rule] == NODEPHP_STATIC) {
488 | return serveStatic(pathname, __script_dir__, response, request);
489 | } else if (block[rule] == NODEPHP_FCGI) {
490 | return serveFpm(script_file, __script_dir__, request, response, params, options);
491 | }
492 | }
493 | }
494 |
495 | // If we get here, it means we didn't find a PHP file and we didn't find a static file. Might
496 | // be time for a rewrite and our rewrites are simple: /index?...
497 | var default_index = block['index'] || '/index.php';
498 | serveFpm(default_index, __script_dir__, request, response, params, options);
499 |
500 | }).listen(options.server.port);
501 |
502 | console.log("PHP Server is now running on http://" + options.server.host + ":" + options.server.port);
503 | };
504 |
505 | /**
506 | * Even though some people hate this (With good reasons)
507 | * I find it works very well for what I need and I don't
508 | * have time to implement somethign more clever.
509 | *
510 | * Enjoy and if you want comments and ideas about this, see
511 | * my link: http://onemoredigit.com/post/1527191998/extending-objects-in-node-js
512 | */
513 | Object.defineProperty(Object.prototype, "extend", {
514 | enumerable: false,
515 | value: function(from) {
516 | var props = Object.getOwnPropertyNames(from);
517 | var dest = this;
518 | props.forEach(function(name) {
519 | if (name in dest) {
520 | var destination = Object.getOwnPropertyDescriptor(from, name);
521 | Object.defineProperty(dest, name, destination);
522 | }
523 | });
524 | return this;
525 | }
526 | });
527 | exports.nodephp = createServer;
528 |
529 | exports.NODEPHP_TYPE_STATIC = NODEPHP_STATIC;
530 | exports.NODEPHP_TYPE_FCGI = NODEPHP_FCGI;
531 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name" : "nodephp",
3 | "version" : "0.1.1",
4 | "description" : "A node.js web-server that interacts with PHP-FPM through FastCGI",
5 | "keywords": ["php", "webserver", "rad", "fastcgi", "php-fpm"],
6 | "homepage": "http://github.com/davidcoallier/node-php",
7 | "tag": "pre-alpha",
8 | "repository": {
9 | "type": "git",
10 | "url": "git://github.com/davidcoallier/node-php.git"
11 | },
12 | "author" : "David Coallier