======================================= PHP BASIC OPEN_BASEDIR CONCEPT ======================================= Files and media can be protected by storing them outside of the document root so that there is no direct access to them. A script could then be used to validate a request and decide to serve it or not. We can extend this feature and move ALL files outside of the htdocs directory. The htdocs directory would be keep to a bare minimum. /path/to/site/ | |_ htdocs/ | |_ .htaccess | |_ index.php | |_ base/ |_ about.php |_ error.php |_ index.php |_ test.php | |_ public/ | | | |_ css/ | | |_ bootstrap.min.css | | |_ site.min.css | | | |_ js/ | | |_ bootstrap.min.js | | |_ jquery.min.js | | |_ site.min.js | | | |_images/ | |_batman.jpg | |_ private/ | |_ images/ |_ batman.jpg All urls will have no suffixes to hide the language that is used and all urls with get vars will be simplified. For example these pretty urls would be valid https://www.site.foo https://www.site.foo/ https://www.site.foo/file https://www.site.foo/file/var0/var1/var2/var3 and these urls would generate error 404 https://www.site.foo/index https://www.site.foo/index.php https://www.site.foo/file.php This example uses jquery and bootstrap to demonstrate how files can be installed and served up from outside of the document root. https://code.jquery.com/jquery-3.7.0.min.js https://github.com/twbs/bootstrap/releases/download/v4.6.2/bootstrap-4.6.2-dist.zip ======================================= apache www.site.foo.conf --------------------------------------- Add open_basedir directive to the apache site configuration .conf file. DocumentRoot "/path/to/site/htdocs" Options -Indexes php_admin_value open_basedir "/path/to/site/" ======================================= .htaccess --------------------------------------- RewriteEngine on # custom error page ErrorDocument 400 /error ErrorDocument 401 /error ErrorDocument 403 /error ErrorDocument 404 /error ErrorDocument 405 /error ErrorDocument 406 /error ErrorDocument 407 /error ErrorDocument 408 /error ErrorDocument 409 /error ErrorDocument 410 /error ErrorDocument 411 /error ErrorDocument 412 /error ErrorDocument 413 /error ErrorDocument 414 /error ErrorDocument 415 /error ErrorDocument 416 /error ErrorDocument 417 /error ErrorDocument 421 /error ErrorDocument 422 /error ErrorDocument 423 /error ErrorDocument 424 /error ErrorDocument 426 /error ErrorDocument 429 /error ErrorDocument 431 /error ErrorDocument 451 /error ErrorDocument 500 /error ErrorDocument 501 /error ErrorDocument 502 /error ErrorDocument 503 /error ErrorDocument 504 /error ErrorDocument 505 /error ErrorDocument 506 /error ErrorDocument 507 /error ErrorDocument 508 /error ErrorDocument 510 /error ErrorDocument 511 /error # pass everything to index.php RewriteRule ^/*$ index.php?uri=%{REQUEST_URI} [NC,END] RewriteRule ^([a-zA-Z0-9]+)/*$ index.php?uri=%{REQUEST_URI}&file=$1 [NC,END] RewriteRule ^([a-zA-Z0-9]+)/([^/]+)/*$ index.php?uri=%{REQUEST_URI}&file=$1&v0=$2 [NC,END] RewriteRule ^([a-zA-Z0-9]+)/([^/]+)/([^/]+)/*$ index.php?uri=%{REQUEST_URI}&file=$1&v0=$2&v1=$3 [NC,END] RewriteRule ^([a-zA-Z0-9]+)/([^/]+)/([^/]+)/([^/]+)/*$ index.php?uri=%{REQUEST_URI}&file=$1&v0=$2&v1=$3&v2=$4 [NC,END] RewriteRule ^([a-zA-Z0-9]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/*$ index.php?uri=%{REQUEST_URI}&file=$1&v0=$2&v1=$3&v2=$4&v3=$5 [NC,END] RewriteRule ^([a-zA-Z0-9]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/*$ index.php?uri=%{REQUEST_URI}&file=$1&v0=$2&v1=$3&v2=$4&v3=$5&v4=$6 [NC,END] RewriteRule ^([a-zA-Z0-9]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/([^/]+)/*$ index.php?uri=%{REQUEST_URI}&file=$1&v0=$2&v1=$3&v2=$4&v3=$5&v4=$6&v5=$7 [NC,END] ======================================= /path/to/site/htdocs/index.php --------------------------------------- ======================================= /path/to/site/base/inc_ini.php --------------------------------------- ======================================= /path/to/site/base/inc_inc.php --------------------------------------- ======================================= /path/to/site/base/inc_nav.php --------------------------------------- ======================================= /path/to/site/base/error.php --------------------------------------- 'Continue', 101 => 'Switching Protocols', 102 => 'Processing', 200 => 'OK', 201 => 'Created', 202 => 'Accepted', 203 => 'Non-Authoritative Information', 204 => 'No Content', 205 => 'Reset Content', 206 => 'Partial Content', 207 => 'Multi-Status', 226 => 'IM Used', 300 => 'Multiple Choices', 301 => 'Moved Permanently', 302 => 'Found', 303 => 'See Other', 304 => 'Not Modified', 305 => 'Use Proxy', 306 => 'Reserved', 307 => 'Temporary Redirect', 400 => 'Bad Request', 401 => 'Unauthorized', 402 => 'Payment Required', 403 => 'Forbidden', 404 => 'Not Found', 405 => 'Method Not Allowed', 406 => 'Not Acceptable', 407 => 'Proxy Authentication Required', 408 => 'Request Timeout', 409 => 'Conflict', 410 => 'Gone', 411 => 'Length Required', 412 => 'Precondition Failed', 413 => 'Payload Too Large', 414 => 'URI Too Long', 415 => 'Unsupported Media Type', 416 => 'Range Not Satisfiable', 417 => 'Expectation Failed', 418 => 'I\'m a teapot', 421 => 'Misdirected Request', 422 => 'Unprecessable Entity', 423 => 'Locked', 424 => 'Failed Dependency', 425 => 'Too Early', 426 => 'Upgrade Required', 428 => 'Precondition Required', 429 => 'Too Many Requests', 431 => 'Request Header Fields Too Large', 451 => 'Unavailable For Legal Reasons', 500 => 'Internal Server Error', 501 => 'Not Implemented', 502 => 'Bad Gateway', 503 => 'Service Unavailable', 504 => 'Gateway Timeout', 505 => 'HTTP Version Not Supported', 506 => 'Variant Also Negotiates', 507 => 'Insufficient Storage', 508 => 'Loop Detected', 510 => 'Not Extended', 511 => 'Network Authentication Required' ); if(isset($_SERVER['REDIRECT_STATUS']) && !empty($_SERVER['REDIRECT_STATUS']) && is_numeric($_SERVER['REDIRECT_STATUS']) && $_SERVER['REDIRECT_STATUS'] != 200 && array_key_exists($_SERVER['REDIRECT_STATUS'], $status)) { $err['code'] = $_SERVER['REDIRECT_STATUS']; $err['text'] = $status[$_SERVER['REDIRECT_STATUS']]; } else { $err['code'] = 404; $err['text'] = 'Not Found'; } ?> <?php print($err['code'].' '.$err['text']); ?>
');
print('name: /path/to/site/'.basename($_SERVER['SCRIPT_FILENAME']).'
'); print('file: /path/to/site/'.basename(__FILE__).'
'); if(isset($_GET) && !empty($_GET)) { print('
'.'GET:'.'
'); foreach($_GET as $key => $val) { print('['.$key.'] => '.$val.'
'); } } if(isset($_POST) && !empty($_POST)) { print('
'.'POST:'.'
'); foreach($_POST as $key => $val) { print('['.$key.'] => '.$val.'
'); } } ?>
'.$_SERVER['REQUEST_URI'].''); print('

'.$err['code'].' '.$err['text'].'

'); if(isset($_SERVER['HTTP_REFERER']) && !empty($_SERVER['HTTP_REFERER'])) { print('

referrer: '.$_SERVER['HTTP_REFERER'].'

'); } print('

'.date('Y-m-d H:i:s T').'

'); if(isset($_SERVER['REMOTE_ADDR']) && !empty($_SERVER['REMOTE_ADDR'])) { print('

'.$_SERVER['REMOTE_ADDR'].' : '.$_SERVER['REMOTE_PORT'].'

'); } print('

'.$_SERVER['HTTP_USER_AGENT'].'

'); ?>

======================================= /path/to/site/base/index.php --------------------------------------- open_basedir
');
print('name: /path/to/site/'.basename(dirname($_SERVER['SCRIPT_FILENAME'])).'/'.basename($_SERVER['SCRIPT_FILENAME']).'
'); print('file: /path/to/site/'.basename(dirname(__FILE__)).'/'.basename(__FILE__).'
'); if(isset($_GET) && !empty($_GET)) { print('
'.'GET:'.'
'); foreach($_GET as $key => $val) { print('['.$key.'] => '.$val.'
'); } } if(isset($_POST) && !empty($_POST)) { print('
'.'POST:'.'
'); foreach($_POST as $key => $val) { print('['.$key.'] => '.$val.'
'); } } ?>
======================================= /path/to/site/base/test.php --------------------------------------- open_basedir
');
print('name: /path/to/site/'.basename(dirname($_SERVER['SCRIPT_FILENAME'])).'/'.basename($_SERVER['SCRIPT_FILENAME']).'
'); print('file: /path/to/site/'.basename(dirname(__FILE__)).'/'.basename(__FILE__).'
'); if(isset($_GET) && !empty($_GET)) { print('
'.'GET:'.'
'); foreach($_GET as $key => $val) { print('['.$key.'] => '.$val.'
'); } } if(isset($_POST) && !empty($_POST)) { print('
'.'POST:'.'
'); foreach($_POST as $key => $val) { print('['.$key.'] => '.$val.'
'); } } ?>
Public Image

Accessible for PUBLIC viewing

<img src="/public/image/batman.jpg">

Private Image

Accessible for PRIVATE viewing

<img src="/private/image/batman.jpg">

======================================= /path/to/site/base/about.php --------------------------------------- open_basedir
');
print('name: /path/to/site/'.basename(dirname($_SERVER['SCRIPT_FILENAME'])).'/'.basename($_SERVER['SCRIPT_FILENAME']).'
'); print('file: /path/to/site/'.basename(dirname(__FILE__)).'/'.basename(__FILE__).'
'); if(isset($_GET) && !empty($_GET)) { print('
'.'GET:'.'
'); foreach($_GET as $key => $val) { print('['.$key.'] => '.$val.'
'); } } if(isset($_POST) && !empty($_POST)) { print('
'.'POST:'.'
'); foreach($_POST as $key => $val) { print('['.$key.'] => '.$val.'
'); } } ?>
======================================= /path/to/site/base/public.php --------------------------------------- $val) { if($key != 'uri' && $key != 'file' && $val != '.' && $val != '..') { $file_test .= '/'.$val; } } $file = BASE.'/'.$file_test; if(is_file($file)) { header('Content-Disposition: inline; filename="'.basename($file).'"'); $ext = pathinfo($file, PATHINFO_EXTENSION); if($ext == 'css') { header('Content-type: text/css'); } elseif($ext == 'js') { header('Content-type: text/javascript'); } elseif($ext == 'txt') { header('Content-type: text/plain'); } elseif($ext == 'jpg') { header('Content-type: image/jpg'); } elseif($ext == 'png') { header('Content-type: image/png'); } else { $finfo = finfo_open(FILEINFO_MIME); $mime = explode(';', finfo_file($finfo, $file))[0]; header('Content-Type: '.$mime); header('Connection: Keep-Alive'); header('Keep-Alive: timeout=5 max=100'); header('Accept-Ranges: bytes'); } header('Content-Length:'.filesize($file)); readfile($file); } else { $_SERVER['REDIRECT_STATUS'] = 404; $file = BASE.'/error.php'; require_once($file); } ?> ======================================= /path/to/site/base/private.php --------------------------------------- $val) { if($key != 'uri' && $key != 'file' && $val != '.' && $val != '..') { $file_test .= '/'.$val; } } $file = BASE.'/'.$file_test; if(is_file($file) && isset($ok)) { header('Content-Disposition: inline; filename="'.basename($file).'"'); $ext = pathinfo($file, PATHINFO_EXTENSION); if($ext == 'css') { header('Content-type: text/css'); } elseif($ext == 'js') { header('Content-type: text/javascript'); } elseif($ext == 'txt') { header('Content-type: text/plain'); } elseif($ext == 'jpg') { header('Content-type: image/jpg'); } elseif($ext == 'png') { header('Content-type: image/png'); } else { $finfo = finfo_open(FILEINFO_MIME); $mime = explode(';', finfo_file($finfo, $file))[0]; header('Content-Type: '.$mime); header('Connection: Keep-Alive'); header('Keep-Alive: timeout=5 max=100'); header('Accept-Ranges: bytes'); } header('Content-Length:'.filesize($file)); readfile($file); } else { $_SERVER['REDIRECT_STATUS'] = 404; $file = BASE.'/error.php'; require_once($file); } ?> ======================================= demo site --------------------------------------- https://base.oetec.com ======================================= :0) =======================================