NGINX
Intro
- uses an asynchronous event-driven model which provides predictable performance under load
- efficiently serve static content such as HTML and media files
- hands off dynamic content to CGI, FastCGI, or other web servers such as Apache, content is then passed back to NGINX for delivery to the client
- directives (configuration options) are organized into groups known as blocks/contexts
- lines preceded by a # character are comments
- lines containing directives must end with a ;
- VirtualHost is an Apache term, NGINX does not have Virtual hosts, it has “Server Blocks” that use the server_name and listen directives to bind to tcp sockets
- /etc/nginx/ - configuration files
- /etc/nginx/nginx.conf - primary configuration file
- files outside any block are in main context
- events and http blocks are areas for additional directives, and they also exist in the main context
- http - directives for handling web traffic, universal because they are passed on to all website configurations NGINX serves
- include /etc/nginx/conf.d/*.conf; - each website hosted with NGINX should have its own configuration file in /etc/nginx/conf.d/, with the name formatted as example.com.conf, sites which are disabled (not being served by NGINX) should be named example.com.conf.disabled
- include /etc/nginx/sites-enabled/*; - ../sites-enabled/ folder contains symlinks to the site configuration files stored in /etc/nginx/sites-available/, sites in sites-available can be disabled by removing the symlink to sites-enabled
- /etc/nginx/conf.d/default.conf OR etc/nginx/sites-enabled/default - example configuration file
- sites configuration file
- listen directive tells NGINX the hostname/IP and the TCP port where it should listen for HTTP connections., default_server means this virtual host will answer requests on port 80 that dont specifically match another virtual hosts listen statement, the second statement listens over IPv6 and behaves similarly
- server_name directive allows multiple domains to be served from a single IP address, server decides which domain to serve based on the request header it receives
- you typically should create one file per domain or site you want to host on server
- you can specify server names that are not valid domain names, HTTP header are used to answer requests, regardless of whether the domain name is valid or not - useful for LAN servers, or if you already know all of the clients that will be making requests of the server, this includes front-end proxy servers with /etc/hosts entries configured for the IP address on which NGINX is listening
- location setting lets you configure how to respond to requests for resources within the server, like the server_name directive tells how to process requests for the domain, location directives cover requests for specific files and folders, such as http://example.com/blog/, match any part of an HTTP request that comes after the host segment
- location directive followed by a tilde (~) performs a RegEx match, case-sensitive, Perl Compatible Regular Expressions (PCRE), ~* - case-insensitive, ^~ - stop searching for more specific matches and use the directives here instead, = - exact match
- 1 - exact match
- 2 - literal string OR ^~
- 3 - RegEx
- 4 - if no RegEx, then most specific literal string match
- make sure each file and folder under a domain will match at least one location directive
- commands
/usr/bin/nginx
- start
/usr/bin/nginx -s stop
- stop
/usr/bin/nginx -s reload
- reload
sudo service nginx status
OR sudo systemctl status nginx
sudo service nginx start
OR sudo systemctl start nginx
- check apache:
sudo service apache2 status
OR sudo systemctl status apache2
sudo service apache2 stop
OR sudo systemctl stop apache2
sudo nestat -plunt
OR sudo ss -plunt
- LOGS:
/var/log/nginx/access.log
OR /var/log/nginx/error.log
- configuration test:
sudo nginx -t
- namei -om /path/to/check - display all the permissions on a path
- check browser cache
- ADD mime.types for specific file
- if you do not explicitly set "underscores_in_headers on" NGINX will silently drop HTTP headers with underscores
- dont use the default document root for any site-critical files
- never use a hostname in a listen directive
-
https://www.nginx.com/resources/wiki/start/topics/tutorials/commandline/
-
https://www.linode.com/docs/web-servers/nginx/
# ----- /etc/nginx/nginx.conf
user nginx;
worker_processes 1;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
# ...
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] "$request" '
'$status $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
#tcp_nopush on;
keepalive_timeout 65;
#gzip on;
include /etc/nginx/conf.d/*.conf;
}
# ----- /etc/nginx/conf.d/example.com.conf
# ----- /etc/nginx/sites-enabled/default
server {
listen 80 default_server; # where to listen for HTTP connections
listen [::]:80 default_server;
# listen 127.0.0.16:80; # never listen hostname
server_name example.com www.example.com;
# server_name *.example.com; # serve all sub-doamains
# server_name .example.com; # serve all sub-doamains
# server_name example.*; # all domain names beginning with example.
root /var/www/example.com; # avoid using / only, vulnerability !
index index.html; # which file to serve if none is specified
try_files $uri /index.html;
# initial location
location / {
# avoid root in initial location
root /var/www/example.com;
# index is already defined, no need, it is inherited ...
index index.html index.htm;
}
location /bar {
root /some/other/place; # root for THIS location, index already defined
# [...]
}
# use $request_filename instead of $document_root$fastcgi_script_name,
# usage of alias directive with $document_root$fastcgi_script_name,
# $document_root$fastcgi_script_name will return the wrong path
location /api/ {
index index.php index.html index.htm;
alias /app/www/;
location ~* "\.php$" {
try_files $uri =404;
fastcgi_pass 127.0.0.1:9000;
fastcgi_param SCRIPT_FILENAME $request_filename;
}
}
# specific
location /images/ { }
location /blog/ { }
location /planet/ { }
# more specific
location /planet/blog/ { }
# RegEx, case-sensitive requests
# case-sensitive
location ~ IndexPage\.php$ { }
location ~ ^/BlogPlanet(/|/index\.php)$ { } # /BlogPlanet/ and /BlogPlanet/index.php
# case-insensitive
location ~* \.(pl|cgi|perl|prl)$ { }
location ~* \.(md|mdwn|txt|mkdn)$ { }
# intercept and process
location ^~ /images/IndexPage/ { }
location ^~ /blog/BlogPlanet/ { }
# exact
location = / { }
}
# serve static first, then scripts
server {
server_name _;
root /var/www/site;
location / {
try_files $uri $uri/ @proxy;
# try_files $uri $uri/ /index.php;
}
location @proxy {
# location ~ \.php$ {
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_pass unix:/tmp/phpcgi.socket;
}
}
# serving static files
server {
server_name www.domain1.com;
access_log logs/domain1.access.log main;
error_log logs/domain1.error error;
root /var/www/domain1.com/htdocs;
}
server {
server_name www.domain2.com;
access_log logs/domain2.access.log main;
error_log logs/domain2.error error;
root /var/www/domain2.com/htdocs;
}
# catch all
server {
listen 80 default_server;
server_name _; # This is just an invalid value which will never trigger on a real hostname.
access_log logs/default.access.log main;
server_name_in_redirect off;
root /var/www/default/htdocs;
}
# easy way to keep adding new subdomains
server {
# Replace this port with the right one for requirements
listen 80 default_server; #could also be 1.2.3.4:80
# Multiple hostnames separated by spaces. Replace these as well.
server_name star.yourdomain.com *.yourdomain.com; # Alternately: _
root /PATH/TO/WEBROOT;
error_page 404 errors/404.html;
access_log logs/star.yourdomain.com.access.log;
index index.php index.html index.htm;
# static file 404's aren't logged and expires header is set to maximum age
location ~* \.(jpg|jpeg|gif|css|png|js|ico|html)$ {
access_log off;
expires max;
}
location ~ \.php$ {
include fastcgi_params;
fastcgi_intercept_errors on;
# By all means use a different server for the fcgi processes if you need to
fastcgi_pass 127.0.0.1:YOURFCGIPORTHERE;
}
location ~ /\.ht {
deny all;
}
}
# avoid IF clause, use:
server {
server_name www.example.com;
return 301 $scheme://example.com$request_uri;
}
server {
server_name example.com;
# [...]
}
# avoid IF-file checking, use:
server {
root /var/www/example.com;
location / {
try_files $uri $uri/ /index.html;
}
}
try_files $uri $uri/ /index.php?q=$uri&$args;
# checking as url, then as directory/, then serve with default /index.php
try_files $uri $uri/ /index.php;
# process only specific files
# + cgi.fix_pathinfo=0 in php.ini - to stop processing if the file is not found
location ~* (file_a|file_b|file_c)\.php$ {
fastcgi_pass backend;
# [...]
}
# disable the execution of PHP files in any directory
location /uploaddir {
location ~ \.php$ {return 403;}
# [...]
}
# filter out the problem condition
location ~* \.php$ {
try_files $uri = 404;
fastcgi_pass backend;
# [...]
}
# ... nested
location ~* \.php$ {
location ~ \..*/.*\.php$ {return 404;}
fastcgi_pass backend;
# [...]
}
# REWRITE
# $request_uri for capturing
# rewrite ^/(.*)$ http://example.com/$1 permanent; # BAD
rewrite ^ http://example.com$request_uri? permanent;
return 301 http://example.com$request_uri;
# rewrites are relative unless you tell NGINX that theyre not
# rewrite ^ example.com permanent; # BAD
rewrite ^ http://example.com permanent;
# it is advised to not use SSLv3
# provide only the TLS protocols instead
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
Full example 1
nginx.conf
user www www; ## Default: nobody
worker_processes 5; ## Default: 1
error_log logs/error.log;
pid logs/nginx.pid;
worker_rlimit_nofile 8192;
events {
worker_connections 4096; ## Default: 1024
}
http {
include conf/mime.types;
include /etc/nginx/proxy.conf;
include /etc/nginx/fastcgi.conf;
index index.html index.htm index.php;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] $status '
'"$request" $body_bytes_sent "$http_referer" '
'"$http_user_agent" "$http_x_forwarded_for"';
access_log logs/access.log main;
sendfile on;
tcp_nopush on;
server_names_hash_bucket_size 128; # this seems to be required for some vhosts
server { # php/fastcgi
listen 80;
server_name domain1.com www.domain1.com;
access_log logs/domain1.access.log main;
root html;
location ~ \.php$ {
fastcgi_pass 127.0.0.1:1025;
}
}
server { # simple reverse-proxy
listen 80;
server_name domain2.com www.domain2.com;
access_log logs/domain2.access.log main;
# serve static files
location ~ ^/(images|javascript|js|css|flash|media|static)/ {
root /var/www/virtual/big.server.com/htdocs;
expires 30d;
}
# pass requests for dynamic content to rails/turbogears/zope, et al
location / {
proxy_pass http://127.0.0.1:8080;
}
}
upstream big_server_com {
server 127.0.0.3:8000 weight=5;
server 127.0.0.3:8001 weight=5;
server 192.168.0.1:8000;
server 192.168.0.1:8001;
}
server { # simple load balancing
listen 80;
server_name big.server.com;
access_log logs/big.server.access.log main;
location / {
proxy_pass http://big_server_com;
}
}
}
proxy.conf
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_buffers 32 4k;
fastcgi.conf
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
fastcgi_index index.php;
fastcgi_param REDIRECT_STATUS 200;
mime.types
types {
text/html html htm shtml;
text/css css;
text/xml xml rss;
image/gif gif;
image/jpeg jpeg jpg;
application/x-javascript js;
text/plain txt;
text/x-component htc;
text/mathml mml;
image/png png;
image/x-icon ico;
image/x-jng jng;
image/vnd.wap.wbmp wbmp;
application/java-archive jar war ear;
application/mac-binhex40 hqx;
application/pdf pdf;
application/x-cocoa cco;
application/x-java-archive-diff jardiff;
application/x-java-jnlp-file jnlp;
application/x-makeself run;
application/x-perl pl pm;
application/x-pilot prc pdb;
application/x-rar-compressed rar;
application/x-redhat-package-manager rpm;
application/x-sea sea;
application/x-shockwave-flash swf;
application/x-stuffit sit;
application/x-tcl tcl tk;
application/x-x509-ca-cert der pem crt;
application/x-xpinstall xpi;
application/zip zip;
application/octet-stream deb;
application/octet-stream bin exe dll;
application/octet-stream dmg;
application/octet-stream eot;
application/octet-stream iso img;
application/octet-stream msi msp msm;
audio/mpeg mp3;
audio/x-realaudio ra;
video/mpeg mpeg mpg;
video/quicktime mov;
video/x-flv flv;
video/x-msvideo avi;
video/x-ms-wmv wmv;
video/x-ms-asf asx asf;
video/x-mng mng;
}
Full example 2
nginx.conf
user www www;
worker_processes 2;
pid /var/run/nginx.pid;
# [ debug | info | notice | warn | error | crit ]
error_log /var/log/nginx.error_log info;
events {
worker_connections 2000;
# use [ kqueue | rtsig | epoll | /dev/poll | select | poll ] ;
use kqueue;
}
http {
include conf/mime.types;
default_type application/octet-stream;
log_format main '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$gzip_ratio"';
log_format download '$remote_addr - $remote_user [$time_local] '
'"$request" $status $bytes_sent '
'"$http_referer" "$http_user_agent" '
'"$http_range" "$sent_http_content_range"';
client_header_timeout 3m;
client_body_timeout 3m;
send_timeout 3m;
client_header_buffer_size 1k;
large_client_header_buffers 4 4k;
gzip on;
gzip_min_length 1100;
gzip_buffers 4 8k;
gzip_types text/plain;
output_buffers 1 32k;
postpone_output 1460;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
send_lowat 12000;
keepalive_timeout 75 20;
# lingering_time 30;
# lingering_timeout 10;
# reset_timedout_connection on;
server {
listen one.example.com;
server_name one.example.com www.one.example.com;
access_log /var/log/nginx.access_log main;
location / {
proxy_pass http://127.0.0.1/;
proxy_redirect off;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 10m;
client_body_buffer_size 128k;
client_body_temp_path /var/nginx/client_body_temp;
proxy_connect_timeout 90;
proxy_send_timeout 90;
proxy_read_timeout 90;
proxy_send_lowat 12000;
proxy_buffer_size 4k;
proxy_buffers 4 32k;
proxy_busy_buffers_size 64k;
proxy_temp_file_write_size 64k;
proxy_temp_path /var/nginx/proxy_temp;
charset koi8-r;
}
error_page 404 /404.html;
location /404.html {
root /spool/www;
charset on;
source_charset koi8-r;
}
location /old_stuff/ {
rewrite ^/old_stuff/(.*)$ /new_stuff/$1 permanent;
}
location /download/ {
valid_referers none blocked server_names *.example.com;
if ($invalid_referer) {
#rewrite ^/ http://www.example.com/;
return 403;
}
# rewrite_log on;
# rewrite /download/*/mp3/*.any_ext to /download/*/mp3/*.mp3
rewrite ^/(download/.*)/mp3/(.*)\..*$ /$1/mp3/$2.mp3 break;
root /spool/www;
# autoindex on;
access_log /var/log/nginx-download.access_log download;
}
location ~* ^.+\.(jpg|jpeg|gif)$ {
root /spool/www;
access_log off;
expires 30d;
}
}
}
ReverseProxy
nginx.conf
server {
listen 80;
listen [::]:80;
server_name example.com;
location / {
proxy_pass http://localhost:3000/;
}
}
# + caching
http {
proxy_cache_path /data/nginx/cache levels=1:2 keys_zone=STATIC:10m
inactive=24h max_size=1g;
server {
location / {
proxy_pass http://1.2.3.4;
proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr;
proxy_buffering on;
proxy_cache STATIC;
proxy_cache_valid 200 1d;
proxy_cache_use_stale error timeout invalid_header updating
http_500 http_502 http_503 http_504;
}
}
}
Load Balancing
nginx.conf
http {
upstream myproject {
server 127.0.0.1:8000 weight=3;
server 127.0.0.1:8001;
server 127.0.0.1:8002;
server 127.0.0.1:8003;
}
server {
listen 80;
server_name www.domain.com;
location / {
proxy_pass http://myproject;
}
}
}
PHP FastCGI
- this guide assume PHP FPM already installed and configured either using tcp port (127.0.0.1:9000) or unix socket (/var/run/php-fpm.sock)
- restart and test
<?php var_export($_SERVER)?<
with /test.php , /test.php/ , /test.php/foo/test.php/foo/bar.php , /test.php/foo/bar.php?v=1
- pay attention to the value of REQUEST_URI, SCRIPT_FILENAME, SCRIPT_NAME, PATH_INFO and PHP_SELF
- 1) location regex capable to handle PATH_INFO and properly check that the extension indeed .php (not .phps) whether there is PATH_INFO or not
- 2) fastcgi_split_path_info regex capable to correctly handle request like /test.php/foo/blah.php or /test.php/
- 3) the if lets NGINX check whether the *.php does indeed exist to prevent NGINX to feeding PHP FPM non php script file (like uploaded image)
- 4) SCRIPT_FILENAME parameter is required as it is passed to PHP FPM to determine the script name, for a lot of Linux distributions, this parameter has been added in fastcgi_params file, i.e. /etc/nginx/fastcgi_params``so the users could import all the CGI params via the ``include directive, i.e. include fastcgi_params, but for some distributions, such as CentOS, this parameter does not exist in fastcgi_params file, if this parameter is not set, PHP FPM responses 200 OK with empty content, and there is no error or warning. For more informaton about the CGI params, please refer to nginx beginners guide, $_SERVER in PHP and RFC3875
- 5) if you see a blank page in browser, please check if SCRIPT_FILENAME parameter is set
- 6) this guide run fine on php.ini with cgi.fix_pathinfo = 1 (the default), some guide insist to change it to cgi.fix_pathinfo = 0 but doing that make PHP_SELF variable broken (not equal to DOCUMENT_URI)
php-fpm commands
# FPM status
systemctl status php7.0-fpm.service
# locate PHP configuration files
find / \( -iname "php.ini" -o -name "www.conf" \)
# listen.owner and listen.group variables are set to www-data by default,
# but they need to match the user and group NGINX is running as, verify
ps -aux | grep nginx
# output
root 3448 0.0 0.0 32500 3516 ? Ss 18:21 0:00 nginx: master process / usr/sbin/nginx -c /etc/nginx/nginx.conf
nginx 3603 0.0 0.0 32912 2560 ? S 18:24 0:00 nginx: worker process
nginx 3604 0.0 0.0 32912 3212 ? S 18:24 0:00 nginx: worker process
# change the listen variables
sed -i 's/listen.owner = www-data/listen.owner = nginx/g' /etc/php/7.0/fpm/pool.d/www.conf
sed -i 's/listen.group = www-data/listen.group = nginx/g' /etc/php/7.0/fpm/pool.d/www.conf
# prevent processing unexistent files
sed -i 's/;cgi.fix_pathinfo=1/cgi.fix_pathinfo=0/g' /etc/php/7.0/fpm/php.ini
# restart
systemctl restart php7.0-fpm.service
/etc/nginx/fastcgi_params
fastcgi_param QUERY_STRING $query_string;
fastcgi_param REQUEST_METHOD $request_method;
fastcgi_param CONTENT_TYPE $content_type;
fastcgi_param CONTENT_LENGTH $content_length;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
fastcgi_param SCRIPT_NAME $fastcgi_script_name;
fastcgi_param PATH_INFO $fastcgi_path_info;
fastcgi_param PATH_TRANSLATED $document_root$fastcgi_path_info;
fastcgi_param REQUEST_URI $request_uri;
fastcgi_param DOCUMENT_URI $document_uri;
fastcgi_param DOCUMENT_ROOT $document_root;
fastcgi_param SERVER_PROTOCOL $server_protocol;
fastcgi_param GATEWAY_INTERFACE CGI/1.1;
fastcgi_param SERVER_SOFTWARE nginx/$nginx_version;
fastcgi_param REMOTE_ADDR $remote_addr;
fastcgi_param REMOTE_PORT $remote_port;
fastcgi_param SERVER_ADDR $server_addr;
fastcgi_param SERVER_PORT $server_port;
fastcgi_param SERVER_NAME $server_name;
fastcgi_param HTTPS $https;
# PHP only, required if PHP was built with --enable-force-cgi-redirect
fastcgi_param REDIRECT_STATUS 200;
nginx.conf
# proxy requests to PHP FPM via the FCGI protocol
location ~ [^/]\.php(/|$) {
fastcgi_split_path_info ^(.+?\.php)(/.*)$;
if (!-f $document_root$fastcgi_script_name) {
return 404;
}
# Mitigate https://httpoxy.org/ vulnerabilities
fastcgi_param HTTP_PROXY "";
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
# for unix socket change fastcgi_pass
# fastcgi_pass unix:/var/run/php-fpm.sock;
# include the fastcgi_param setting
include fastcgi_params;
# SCRIPT_FILENAME parameter is used for PHP FPM determining
# the script name. If it is not set in fastcgi_params file,
# i.e. /etc/nginx/fastcgi_params or in the parent contexts,
# please comment off following line:
# fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
correct output for http://lemp.test/test.php/foo/bar.php?v=1
array (
'USER' => 'www-data',
'HOME' => '/var/www',
'FCGI_ROLE' => 'RESPONDER',
'QUERY_STRING' => 'v=1',
'REQUEST_METHOD' => 'GET',
'CONTENT_TYPE' => '',
'CONTENT_LENGTH' => '',
'SCRIPT_FILENAME' => '/var/www/test.php',
'SCRIPT_NAME' => '/test.php',
'PATH_INFO' => '/foo/bar.php',
'REQUEST_URI' => '/test.php/foo/bar.php?v=1',
'DOCUMENT_URI' => '/test.php/foo/bar.php',
'DOCUMENT_ROOT' => '/var/www',
'SERVER_PROTOCOL' => 'HTTP/1.1',
'GATEWAY_INTERFACE' => 'CGI/1.1',
'SERVER_SOFTWARE' => 'nginx/1.4.0',
'REMOTE_ADDR' => '192.168.56.1',
'REMOTE_PORT' => '44644',
'SERVER_ADDR' => '192.168.56.3',
'SERVER_PORT' => '80',
'SERVER_NAME' => '',
'HTTPS' => '',
'REDIRECT_STATUS' => '200',
'HTTP_HOST' => 'lemp.test',
'HTTP_USER_AGENT' => 'Mozilla/5.0 (X11; Ubuntu; Linux x86_64; rv:20.0) Gecko/20100101 Firefox/20.0',
'HTTP_ACCEPT' => 'text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8',
'HTTP_ACCEPT_LANGUAGE' => 'en-US,en;q=0.5',
'HTTP_ACCEPT_ENCODING' => 'gzip, deflate',
'HTTP_CONNECTION' => 'keep-alive',
'PHP_SELF' => '/test.php/foo/bar.php',
'REQUEST_TIME' => 1367829847,
)
Recompile
Back to Main Page