Skip to content

Instantly share code, notes, and snippets.

@rmpel
Last active June 11, 2022 09:30
Show Gist options
  • Save rmpel/11583cfddfcc9705578428e3a2ee3dc1 to your computer and use it in GitHub Desktop.
Save rmpel/11583cfddfcc9705578428e3a2ee3dc1 to your computer and use it in GitHub Desktop.
apache_request_headers drop-in function for PHP as FPM
<?php
// Drop-in replacement for apache_request_headers() when it's not available
if ( ! function_exists( 'apache_request_headers' ) ) {
function apache_request_headers() {
static $arrHttpHeaders;
if ( ! $arrHttpHeaders ) {
// Based on: http://www.iana.org/assignments/message-headers/message-headers.xml#perm-headers
$arrCasedHeaders = array(
// HTTP
'Dasl' => 'DASL',
'Dav' => 'DAV',
'Etag' => 'ETag',
'Mime-Version' => 'MIME-Version',
'Slug' => 'SLUG',
'Te' => 'TE',
'Www-Authenticate' => 'WWW-Authenticate',
// MIME
'Content-Md5' => 'Content-MD5',
'Content-Id' => 'Content-ID',
'Content-Features' => 'Content-features',
);
$arrHttpHeaders = array();
foreach ( $_SERVER as $strKey => $mixValue ) {
if ( 'HTTP_' !== substr( $strKey, 0, 5 ) ) {
continue;
}
$strHeaderKey = strtolower( substr( $strKey, 5 ) );
if ( 0 < substr_count( $strHeaderKey, '_' ) ) {
$arrHeaderKey = explode( '_', $strHeaderKey );
$arrHeaderKey = array_map( 'ucfirst', $arrHeaderKey );
$strHeaderKey = implode( '-', $arrHeaderKey );
} else {
$strHeaderKey = ucfirst( $strHeaderKey );
}
if ( array_key_exists( $strHeaderKey, $arrCasedHeaders ) ) {
$strHeaderKey = $arrCasedHeaders[ $strHeaderKey ];
}
$arrHttpHeaders[ $strHeaderKey ] = $mixValue;
}
/** in case you need authorization and your hosting provider has not fixed this for you:
* VHOST-Config:
* FastCgiExternalServer line needs -pass-header Authorization
*
* .htaccess or VHOST-config file needs:
* SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1
* to add the Authorization header to the environment for further processing
*/
if ( ! empty( $arrHttpHeaders['Authorization'] ) ) {
// in case of Authorization, but the values not propagated properly, do so :)
if ( ! isset( $_SERVER['PHP_AUTH_USER'] ) ) {
list( $_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW'] ) = explode( ':', base64_decode( substr( $_SERVER['HTTP_AUTHORIZATION'], 6 ) ) );
}
}
}
return $arrHttpHeaders;
}
// execute now so other scripts have little chance to taint the information in $_SERVER
// the data is cached, so multiple retrievals of the headers will not cause further impact on performance.
apache_request_headers();
}
@gebeer
Copy link

gebeer commented Sep 9, 2018

You have a typo on line 57 $arrHttHeaders (p missing) must be changed to read $arrHttpHeaders twice.
Guess nobody has has used this with Authorization header, yet :)

@studioxyz
Copy link

Thanks so much for this! I just switched over to php-fpm and this proved to be a quick fix to get up and running again. At least until upgrading from PHP 7.2. Thanks again!

@rmpel
Copy link
Author

rmpel commented May 25, 2020

@studioxyz: You're welcome, but please be aware of the typo on line 57. I just fixed it.
@gebeer: Wow. just ... wow ... I never got a notification of your comment and I am stunned I never had a problem with this... THANK YOU! I have fixed the typo :).

@studioxyz
Copy link

@rmpel Ah, thanks for the heads-up! I just fixed it on my copy. I’m not using Authorization in this application so I don't think I was affected, but I’m glad it won’t cause problems in the future.

@chiragmshah70
Copy link

@rmpel - I get internal server error 500.

@rmpel
Copy link
Author

rmpel commented Jun 11, 2022

@chiragmshah70 - And what does your error log say? what is the fatal error exactly? Which PHP version are you using?

@chiragmshah70
Copy link

I am using PHP 7.2. my header.php file used before the database connection looks like the following.

'DASL', 'Dav' => 'DAV', 'Etag' => 'ETag', 'Mime-Version' => 'MIME-Version', 'Slug' => 'SLUG', 'Te' => 'TE', 'Www-Authenticate' => 'WWW-Authenticate', // MIME 'Content-Md5' => 'Content-MD5', 'Content-Id' => 'Content-ID', 'Content-Features' => 'Content-features', ); $arrHttpHeaders = array(); foreach($_SERVER as $strKey => $mixValue) { if('HTTP_' !== substr($strKey, 0, 5)) { continue; } $strHeaderKey = strtolower(substr($strKey, 5)); if(0 < substr_count($strHeaderKey, '_')) { $arrHeaderKey = explode('_', $strHeaderKey); $arrHeaderKey = array_map('ucfirst', $arrHeaderKey); $strHeaderKey = implode('-', $arrHeaderKey); } else { $strHeaderKey = ucfirst($strHeaderKey); } if(array_key_exists($strHeaderKey, $arrCasedHeaders)) { $strHeaderKey = $arrCasedHeaders[$strHeaderKey]; } $arrHttpHeaders[$strHeaderKey] = $mixValue; } /** in case you need authorization and your hosting provider has not fixed this for you: * VHOST-Config: * FastCgiExternalServer line needs -pass-header Authorization * * .htaccess or VHOST-config file needs: SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1 * to add the Authorization header to the environment for further processing */ if (isset($arrHttpHeaders['Authorization']) && $arrHttpHeaders['Authorization']) { // in case of Authorization, but the values not propagated properly, do so :) if (!isset($_SERVER['PHP_AUTH_USER'])) { list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':' , base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6))); } } } return $arrHttpHeaders; } // execute now so other scripts have little chance to taint the information in $_SERVER // the data is cached, so multiple retrievals of the headers will not cause further impact on performance. $headers = apache_request_headers(); } else $headers = apache_request_headers(); } if(isset($headers['Authorization'])) { $authorization = $headers['Authorization']; $token='2s5v8y/B?E(H+MbQeThWmYq3t6w9z$C&'; if($authorization!=$token) { echo json_encode(array("Status"=>false,"Message"=>"Invalid Authentication Token.")); exit(); } }else { echo json_encode(array("Status"=>false,"Message"=>"Authentication Token Required.")); exit(); } ?>

@chiragmshah70
Copy link

chiragmshah70 commented Jun 11, 2022

This is htaccess file

RewriteEngine On RewriteBase / RewriteRule ^index\.php$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.php [L] RewriteCond %{HTTP:Authorization} ^(.*) RewriteRule ^(.*) - [E=HTTP_AUTHORIZATION:%1]

SetEnvIf Authorization "(.*)" HTTP_AUTHORIZATION=$1

php_value upload_max_filesize 800M
php_value post_max_size 800M
php_value max_input_time 2000

I have asked the hosting company to provide the log to check fatal error.

@rmpel
Copy link
Author

rmpel commented Jun 11, 2022

please use code-blocks to post code as that will ensure proper formatting. Can't do much with this. Also your first code block seems incomplete. Perhaps that's the problem?
Please include the fatal error fro your log, or use
error_reporting(-1); ini_set('display_errors', 'on');
to show the error on screen.
I'm using the above code in about 300 websites, on php versions ranging from 5.6 to 8.1 (mostly 7.4) and have no problems at all, so it must be something other. Love to help you out, but will need more info :)

@rmpel
Copy link
Author

rmpel commented Jun 11, 2022

@chiragmshah70 I think I may have found your problem.
If I read it correctly, you have altered the code of my gist to read

	// execute now so other scripts have little chance to taint the information in $_SERVER
	// the data is cached, so multiple retrievals of the headers will not cause further impact on performance.
	$headers = apache_request_headers();
} else {
	$headers = apache_request_headers();
}
}

That's not what you should do.

You can embed the code in your own php file, but don't add an "else" class. just use $headers = apache_request_headers(); anywhere in your code., like so;

	// execute now so other scripts have little chance to taint the information in $_SERVER
	// the data is cached, so multiple retrievals of the headers will not cause further impact on performance.
	apache_request_headers();
}
// End of copy-paste code

// ... your own code ...

// Use apache headers like you normally would.
$headers = apache_request_headers();

Also I would suggest not embedding it, but rather download the file to an includes folder and use require_once to load the code.

Furthermore, I don't know what you are trying to do with the Authorization header, with the token, but that seems wrong. The Authorization header is usually something like this;

Authorization: Basic YWxhZGRpbjpvcGVuc2VzYW1l

The code after Basic is base64 encoded and reads the username followed by a colon and ends with the password; aladdin:opensesame
@see: https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Authorization#examples

I am aware my code above does not support the Digest Authorization scheme, but there is no authorization scheme matching your code, so I don't think I can help you with that.

@chiragmshah70
Copy link

@rmpel - Thanks a lot. I refactored the code as suggested above. The authorization string is passed with api call and compared with token to allow API access. The code was breaking and fixed it. now its working. I really appreciate your help. Thanks again.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment