Тема: HTTP Authentication в PHP запущеном как CGI/FastCGI/SuExec

Способ подключения PHP не как SAPI достаточно распространен и удобен, но как и во всем есть нюансы. Я хочу рассказать как можно реализовать такую нужную штуку как HTTP Basic Authentication.

прелюдия

HTTP Basic Authentication - это возможность ограничить доступ к какому-либо http ресурсу (обсуждаем только apache), тоесть тупо попросить логин и пасс. По правилам это делается так

В файлик, например,  .htpasswd записывается пароль в виде webuser:qkbPmuht5Gzgc - это md5 алгоритмом зашифрованй пароль, системная функция crypt(). UNIX неумеет хранить пароли в plaintext формате, а вот Windows умеет. Дальше в .httaccess файл записывается что-то подобное

AuthType Basic
AuthUserFile "/home/username/path_to_htpasswd/.htpasswd"
AuthName “Enter valid username and password!”
require valid-user
<Files my-secret-file.html>
require valid-user
</Files>

и при обращении к данной директории и всем нижестоящим или файлу как в примере будет автоматически потребован пароль. Это очень удобно так как ненужно делать никаких html форм.

Проблема

Точно такой же принцип может применяться и в PHP скриптах для ограничения доступа к какому-либо файлу. НО! это все работает только если PHP подсоединен как SAPI (mod_php) модуль.

<?php
if (!isset($_SERVER['PHP_AUTH_USER'])) {
   header('WWW-Authenticate: Basic realm="My Realm"');
   header('HTTP/1.0 401 Unauthorized');
   echo 'Text to send if user hits Cancel button';
   exit;
 } else {
   echo "<p>Hello, </p>".$_SERVER['PHP_AUTH_USER'];
   echo "<p>You entered as your password: </p>".$_SERVER['PHP_AUTH_PW'];
 }
?>

Вот этот код заставит при вызови скрипта открыть диалоговое окно и попросить логин и пасс, которые в последствии передадутся в переменные $_SERVER['PHP_AUTH_USER'] и $_SERVER['PHP_AUTH_PW']

Все замечательно и красиво, но работает только с mod_php, грустно!

Решение

В решении этой проблемы может помочь mod_rewrite, вообще очень мощная штука при правильном использовании. Для того чтобы перенаправить в скрипт данные из формы мы используетм вот такое правило в .htaccess файле

<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
</IfModule>

Но этого недостаточно, так как данные находятся в несколько неприемлемом формате, поэтому их нужно обработать

list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':' , base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));

после этого переменные $_SERVER['PHP_AUTH_USER'] и $_SERVER['PHP_AUTH_PW'] содержат всю необходимую информацию. Вот работающий пример

<?php
list($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_AUTH_PW']) = explode(':', base64_decode(substr($_SERVER['HTTP_AUTHORIZATION'], 6)));
if (!isset($_SERVER['PHP_AUTH_USER'])) {
   header('WWW-Authenticate: Basic realm="My Realm"');
   header('HTTP/1.0 401 Unauthorized');
   echo 'Text to send if user hits Cancel button';
   exit;
 } else {
   echo "<p>Hello, </p>".$_SERVER['PHP_AUTH_USER'];
   echo "<p>You entered as your password: </p>".$_SERVER['PHP_AUTH_PW'];
 }
?>