package.xml 0000664 0001750 0001750 00000016203 11711007357 011361 0 ustar rui rui
Auth_HTTP
pear.php.net
HTTP authentication
The PEAR::Auth_HTTP class provides methods for creating an HTTP
authentication system using PHP, that is similar to Apache's
realm-based .htaccess authentication.
David Costa
gurugeek
gurugeek@php.net
yes
Rui Hirokawa
hirokawa
hirokawa@php.net
yes
2012-01-28
2.1.8
2.1.8
stable
stable
PHP License
Updated the version of PHP licence from 2.0.2 to 3.0.1.
4.0.0
1.4.0b1
Auth
pear.php.net
1.2.0
1.0
1.0
stable
stable
2001-08-23
PHP License
This is the initial independent release of the Auth_HTTP package.
2.0
2.0
stable
stable
2003-10-16
PHP License
Starting with this release, the code will not be placed in
Auth_HTTP/Auth_HTTP.php anymore. Instead Auth/HTTP.php is used, which
conforms to the PEAR standards.
In order to make use of the new version, you will need to change your
scripts to include the file at the new location! The old version in
Auth_HTTP/Auth_HTTP.php will not be removed when upgrading.
Other changes:
* If it is possible, the session ID will be chosen based on the user's authentication credentials. (Patch by: Marko Karppinen)
* Cleaned up internal variable usage. (Patch by: Brad Bulger)
2.1.0
2.1.0
beta
beta
2004-05-30
PHP License
- Added _sessionName which fixes a major issue with realm sharing.
- Added sessionSharing option to use unique session id.
Currently, this option is set to true by default to maintain
backward compatibility.
- Added setOption and getOption to set/get option value.
- Starting with this release, HTTP Digest Authentication (RFC2617) is
experimentally supported. The code for HTTP Digest Authentication is
originally developed by Tom Pike.
2.1.1
2.1.1
beta
beta
2004-07-12
PHP License
- Fixed a bug #1634 (URI parameter was handled incorrectry.)
2.1.3rc1
2.1.3rc1
beta
beta
2004-08-22
PHP License
- Fixed a bug #2061 (importglobalvariable() was removed in Auth 1.3.0r2.)
- now Auth_HTTP requires Auth >= 1.3.0r2.
2.1.4
2.1.4
stable
stable
2005-01-02
PHP License
- Fixed a bug #2380: constructor couldn't handle non-array option.
- The first stable release with HTTP Digest Authenthication support.
2.1.5
2.1.5
stable
stable
2005-04-02
PHP License
- Fixed a bug #3630 getAuthData failes due to session rename.
2.1.6RC1
2.1.6RC1
beta
beta
2005-04-11
PHP License
- Fixed bug #4047.
- Fixed backward compatibility with PHP 4.x
- Added PHP_AUTH_DIGEST support.
2.1.7
2.1.7
stable
stable
2012-01-26
PHP License
QA release
Bug #7536 Package PEAR never included
Doc Bug #7655 Suggested Adjustments to Documentation
Bug #7784 Auth::start() changes session id
Bug #16742 Please move tests/ to docs/
2.1.8
2.1.8
stable
stable
2012-01-29
PHP License
Updated the version of PHP licence from 2.0.2 to 3.0.1.
Auth_HTTP-2.1.8/Auth/HTTP.php 0000664 0001750 0001750 00000057602 11711007357 013651 0 ustar rui rui |
// | Rui Hirokawa |
// | David Costa |
// +----------------------------------------------------------------------+
//
// $Id$
//
require_once "Auth/Auth.php";
define('AUTH_HTTP_NONCE_TIME_LEN', 16);
define('AUTH_HTTP_NONCE_HASH_LEN', 32);
// {{{ class Auth_HTTP
/**
* PEAR::Auth_HTTP
*
* The PEAR::Auth_HTTP class provides methods for creating an
* HTTP authentication system based on RFC-2617 using PHP.
*
* Instead of generating an HTML driven form like PEAR::Auth
* does, this class sends header commands to the clients which
* cause them to present a login box like they are e.g. used
* in Apache's .htaccess mechanism.
*
* This class requires the PEAR::Auth package.
*
* @notes The HTTP Digest Authentication part is based on
* authentication class written by Tom Pike
*
* @author Martin Jansen
* @author Rui Hirokawa
* @author David Costa
* @package Auth_HTTP
* @extends Auth
* @version $Revision$
*/
class Auth_HTTP extends Auth
{
// {{{ properties
/**
* Authorization method: 'basic' or 'digest'
*
* @access public
* @var string
*/
var $authType = 'basic';
/**
* Name of the realm for Basic Authentication
*
* @access public
* @var string
* @see drawLogin()
*/
var $realm = "protected area";
/**
* Text to send if user hits cancel button
*
* @access public
* @var string
* @see drawLogin()
*/
var $CancelText = "Error 401 - Access denied";
/**
* option array
*
* @access public
* @var array
*/
var $options = array();
/**
* flag to indicate the nonce was stale.
*
* @access public
* @var bool
*/
var $stale = false;
/**
* opaque string for digest authentication
*
* @access public
* @var string
*/
var $opaque = 'dummy';
/**
* digest URI
*
* @access public
* @var string
*/
var $uri = '';
/**
* authorization info returned by the client
*
* @access public
* @var array
*/
var $auth = array();
/**
* next nonce value
*
* @access public
* @var string
*/
var $nextNonce = '';
/**
* nonce value
*
* @access public
* @var string
*/
var $nonce = '';
/**
* Holds a reference to the global server variable
* @var array
*/
var $server;
/**
* Holds a reference to the global post variable
* @var array
*/
var $post;
/**
* Holds a reference to the global cookie variable
* @var array
*/
var $cookie;
// }}}
// {{{ Constructor
/**
* Constructor
*
* @param string Type of the storage driver
* @param mixed Additional options for the storage driver
* (example: if you are using DB as the storage
* driver, you have to pass the dsn string here)
*
* @return void
*/
function Auth_HTTP($storageDriver, $options = '')
{
/* set default values for options */
$this->options = array('cryptType' => 'md5',
'algorithm' => 'MD5',
'qop' => 'auth-int,auth',
'opaquekey' => 'moo',
'noncekey' => 'moo',
'digestRealm' => 'protected area',
'forceDigestOnly' => false,
'nonceLife' => 300,
'sessionSharing' => false,
);
if (!empty($options['authType'])) {
$this->authType = strtolower($options['authType']);
}
if (is_array($options)) {
foreach($options as $key => $value) {
if (array_key_exists( $key, $this->options)) {
$this->options[$key] = $value;
}
}
if (!empty($this->options['opaquekey'])) {
$this->opaque = md5($this->options['opaquekey']);
}
}
$this->Auth($storageDriver, $options);
}
// }}}
// {{{ assignData()
/**
* Assign values from $PHP_AUTH_USER and $PHP_AUTH_PW or 'Authorization' header
* to internal variables and sets the session id based
* on them
*
* @access public
* @return void
*/
function assignData()
{
if (method_exists($this, '_importGlobalVariable')) {
$this->server = &$this->_importGlobalVariable('server');
}
if ($this->authType == 'basic') {
if (!empty($this->server['PHP_AUTH_USER'])) {
$this->username = $this->server['PHP_AUTH_USER'];
}
if (!empty($this->server['PHP_AUTH_PW'])) {
$this->password = $this->server['PHP_AUTH_PW'];
}
/**
* Try to get authentication information from IIS
*/
if (empty($this->username) && empty($this->password)) {
if (!empty($this->server['HTTP_AUTHORIZATION'])) {
list($this->username, $this->password) =
explode(':', base64_decode(substr($this->server['HTTP_AUTHORIZATION'], 6)));
}
}
} elseif ($this->authType == 'digest') {
$this->username = '';
$this->password = '';
$this->digest_header = null;
if (!empty($this->server['PHP_AUTH_DIGEST'])) {
$this->digest_header = $this->server['PHP_AUTH_DIGEST'];
$headers = getallheaders();
} else {
$headers = getallheaders();
if(isset($headers['Authorization']) && !empty($headers['Authorization'])) {
$this->digest_header = substr($headers['Authorization'],
strpos($headers['Authorization'],' ')+1);
}
}
if($this->digest_header) {
$authtemp = explode(',', $this->digest_header);
$auth = array();
foreach($authtemp as $key => $value) {
$value = trim($value);
if(strpos($value,'=') !== false) {
$lhs = substr($value,0,strpos($value,'='));
$rhs = substr($value,strpos($value,'=')+1);
if(substr($rhs,0,1) == '"' && substr($rhs,-1,1) == '"') {
$rhs = substr($rhs,1,-1);
}
$auth[$lhs] = $rhs;
}
}
}
if (!isset($auth['uri']) || !isset($auth['realm'])) {
return;
}
if ($this->selfURI() == $auth['uri']) {
$this->uri = $auth['uri'];
if (substr($headers['Authorization'],0,7) == 'Digest ') {
$this->authType = 'digest';
if (!isset($auth['nonce']) || !isset($auth['username']) ||
!isset($auth['response']) || !isset($auth['qop']) ||
!isset($auth['nc']) || !isset($auth['cnonce'])){
return;
}
if ($auth['qop'] != 'auth' && $auth['qop'] != 'auth-int') {
return;
}
$this->stale = $this->_judgeStale($auth['nonce']);
if ($this->nextNonce == false) {
return;
}
$this->username = $auth['username'];
$this->password = $auth['response'];
$this->auth['nonce'] = $auth['nonce'];
$this->auth['qop'] = $auth['qop'];
$this->auth['nc'] = $auth['nc'];
$this->auth['cnonce'] = $auth['cnonce'];
if (isset($auth['opaque'])) {
$this->auth['opaque'] = $auth['opaque'];
}
} elseif (substr($headers['Authorization'],0,6) == 'Basic ') {
if ($this->options['forceDigestOnly']) {
return; // Basic authentication is not allowed.
}
$this->authType = 'basic';
list($username, $password) =
explode(':',base64_decode(substr($headers['Authorization'],6)));
$this->username = $username;
$this->password = $password;
}
}
} else {
include_once 'PEAR.php';
return PEAR::throwError('authType is invalid.');
}
if ($this->options['sessionSharing'] &&
isset($this->username) && isset($this->password)) {
session_id(md5('Auth_HTTP' . $this->username . $this->password));
}
/**
* set sessionName for AUTH, so that the sessionName is different
* for distinct realms
*/
$this->_sessionName = "_authhttp".md5($this->realm);
}
// }}}
// {{{ login()
/**
* Login function
*
* @access private
* @return void
*/
function login()
{
$login_ok = false;
if (method_exists($this, '_loadStorage')) {
$this->_loadStorage();
}
$this->storage->_auth_obj->_sessionName =& $this->_sessionName;
/**
* When the user has already entered a username,
* we have to validate it.
*/
if (!empty($this->username) && !empty($this->password)) {
if ($this->authType == 'basic' && !$this->options['forceDigestOnly']) {
if (true === $this->storage->fetchData($this->username, $this->password)) {
$login_ok = true;
}
} else { /* digest authentication */
if (!$this->getAuth() || $this->getAuthData('a1') == null) {
/*
* note:
* - only PEAR::DB is supported as container.
* - password should be stored in container as plain-text
* (if $options['cryptType'] == 'none') or
* A1 hashed form (md5('username:realm:password'))
* (if $options['cryptType'] == 'md5')
*/
$dbs = $this->storage;
if (!DB::isConnection($dbs->db)) {
$dbs->_connect($dbs->options['dsn']);
}
$query = 'SELECT '.$dbs->options['passwordcol']." FROM ".$dbs->options['table'].
' WHERE '.$dbs->options['usernamecol']." = '".
$dbs->db->quoteString($this->username)."' ";
$pwd = $dbs->db->getOne($query); // password stored in container.
if (DB::isError($pwd)) {
include_once 'PEAR.php';
return PEAR::throwError($pwd->getMessage(), $pwd->getCode());
}
if ($this->options['cryptType'] == 'none') {
$a1 = md5($this->username.':'.$this->options['digestRealm'].':'.$pwd);
} else {
$a1 = $pwd;
}
$this->setAuthData('a1', $a1, true);
} else {
$a1 = $this->getAuthData('a1');
}
$login_ok = $this->validateDigest($this->password, $a1);
if ($this->nextNonce == false) {
$login_ok = false;
}
}
if (!$login_ok && is_callable($this->loginFailedCallback)) {
call_user_func($this->loginFailedCallback,$this->username, $this);
}
}
if (!empty($this->username) && $login_ok) {
$this->setAuth($this->username);
if (is_callable($this->loginCallback)) {
call_user_func($this->loginCallback,$this->username, $this);
}
}
/**
* If the login failed or the user entered no username,
* output the login screen again.
*/
if (!empty($this->username) && !$login_ok) {
$this->status = AUTH_WRONG_LOGIN;
}
if ((empty($this->username) || !$login_ok) && $this->showLogin) {
$this->drawLogin($this->storage->activeUser);
return;
}
if (!empty($this->username) && $login_ok && $this->authType == 'digest'
&& $this->auth['qop'] == 'auth') {
$this->authenticationInfo();
}
}
// }}}
// {{{ drawLogin()
/**
* Launch the login box
*
* @param string $username Username
* @return void
* @access private
*/
function drawLogin($username = "")
{
/**
* Send the header commands
*/
if ($this->authType == 'basic') {
header("WWW-Authenticate: Basic realm=\"".$this->realm."\"");
header('HTTP/1.0 401 Unauthorized');
} else if ($this->authType == 'digest') {
$this->nonce = $this->_getNonce();
$wwwauth = 'WWW-Authenticate: Digest ';
$wwwauth .= 'qop="'.$this->options['qop'].'", ';
$wwwauth .= 'algorithm='.$this->options['algorithm'].', ';
$wwwauth .= 'realm="'.$this->options['digestRealm'].'", ';
$wwwauth .= 'nonce="'.$this->nonce.'", ';
if ($this->stale) {
$wwwauth .= 'stale=true, ';
}
if (!empty($this->opaque)) {
$wwwauth .= 'opaque="'.$this->opaque.'"' ;
}
$wwwauth .= "\r\n";
if (!$this->options['forceDigestOnly']) {
$wwwauth .= 'WWW-Authenticate: Basic realm="'.$this->realm.'"';
}
header($wwwauth);
header('HTTP/1.0 401 Unauthorized');
}
/**
* This code is only executed if the user hits the cancel
* button or if he enters wrong data 3 times.
*/
if ($this->stale) {
echo 'Stale nonce value, please re-authenticate.';
} else {
echo $this->CancelText;
}
exit;
}
// }}}
// {{{ setRealm()
/**
* Set name of the current realm
*
* @access public
* @param string $realm Name of the realm
* @param string $digestRealm Name of the realm for digest authentication
* @return void
*/
function setRealm($realm, $digestRealm = '')
{
$this->realm = $realm;
if (!empty($digestRealm)) {
$this->options['digestRealm'] = $digestRealm;
}
}
// }}}
// {{{ setCancelText()
/**
* Set the text to send if user hits the cancel button
*
* @access public
* @param string $text Text to send
* @return void
*/
function setCancelText($text)
{
$this->CancelText = $text;
}
// }}}
// {{{ validateDigest()
/**
* judge if the client response is valid.
*
* @access private
* @param string $response client response
* @param string $a1 password or hashed password stored in container
* @return bool true if success, false otherwise
*/
function validateDigest($response, $a1)
{
if (method_exists($this, '_importGlobalVariable')) {
$this->server = &$this->_importGlobalVariable('server');
}
$a2unhashed = $this->server['REQUEST_METHOD'].":".$this->selfURI();
if($this->auth['qop'] == 'auth-int') {
if(isset($GLOBALS["HTTP_RAW_POST_DATA"])) {
// In PHP < 4.3 get raw POST data from this variable
$body = $GLOBALS["HTTP_RAW_POST_DATA"];
} else if($lines = @file('php://input')) {
// In PHP >= 4.3 get raw POST data from this file
$body = implode("\n", $lines);
} else {
if (method_exists($this, '_importGlobalVariable')) {
$this->post = &$this->_importGlobalVariable('post');
}
$body = '';
foreach($this->post as $key => $value) {
if($body != '') $body .= '&';
$body .= rawurlencode($key) . '=' . rawurlencode($value);
}
}
$a2unhashed .= ':'.md5($body);
}
$a2 = md5($a2unhashed);
$combined = $a1.':'.
$this->auth['nonce'].':'.
$this->auth['nc'].':'.
$this->auth['cnonce'].':'.
$this->auth['qop'].':'.
$a2;
$expectedResponse = md5($combined);
if(!isset($this->auth['opaque']) || $this->auth['opaque'] == $this->opaque) {
if($response == $expectedResponse) { // password is valid
if(!$this->stale) {
return true;
} else {
$this->drawLogin();
}
}
}
return false;
}
// }}}
// {{{ _judgeStale()
/**
* judge if nonce from client is stale.
*
* @access private
* @param string $nonce nonce value from client
* @return bool stale
*/
function _judgeStale($nonce)
{
$stale = false;
if(!$this->_decodeNonce($nonce, $time, $hash_cli)) {
$this->nextNonce = false;
$stale = true;
return $stale;
}
if ($time < time() - $this->options['nonceLife']) {
$this->nextNonce = $this->_getNonce();
$stale = true;
} else {
$this->nextNonce = $nonce;
}
return $stale;
}
// }}}
// {{{ _nonceDecode()
/**
* decode nonce string
*
* @access private
* @param string $nonce nonce value from client
* @param string $time decoded time
* @param string $hash decoded hash
* @return bool false if nonce is invalid
*/
function _decodeNonce($nonce, &$time, &$hash)
{
if (method_exists($this, '_importGlobalVariable')) {
$this->server = &$this->_importGlobalVariable('server');
}
if (strlen($nonce) != AUTH_HTTP_NONCE_TIME_LEN + AUTH_HTTP_NONCE_HASH_LEN) {
return false;
}
$time = base64_decode(substr($nonce, 0, AUTH_HTTP_NONCE_TIME_LEN));
$hash_cli = substr($nonce, AUTH_HTTP_NONCE_TIME_LEN, AUTH_HTTP_NONCE_HASH_LEN);
$hash = md5($time . $this->server['HTTP_USER_AGENT'] . $this->options['noncekey']);
if ($hash_cli != $hash) {
return false;
}
return true;
}
// }}}
// {{{ _getNonce()
/**
* return nonce to detect timeout
*
* @access private
* @return string nonce value
*/
function _getNonce()
{
if (method_exists($this, '_importGlobalVariable')) {
$this->server = &$this->_importGlobalVariable('server');
}
$time = time();
$hash = md5($time . $this->server['HTTP_USER_AGENT'] . $this->options['noncekey']);
return base64_encode($time) . $hash;
}
// }}}
// {{{ authenticationInfo()
/**
* output HTTP Authentication-Info header
*
* @notes md5 hash of contents is required if 'qop' is 'auth-int'
*
* @access private
* @param string MD5 hash of content
*/
function authenticationInfo($contentMD5 = '') {
if($this->getAuth() && ($this->getAuthData('a1') != null)) {
$a1 = $this->getAuthData('a1');
// Work out authorisation response
$a2unhashed = ":".$this->selfURI();
if($this->auth['qop'] == 'auth-int') {
$a2unhashed .= ':'.$contentMD5;
}
$a2 = md5($a2unhashed);
$combined = $a1.':'.
$this->nonce.':'.
$this->auth['nc'].':'.
$this->auth['cnonce'].':'.
$this->auth['qop'].':'.
$a2;
// Send authentication info
$wwwauth = 'Authentication-Info: ';
if($this->nonce != $this->nextNonce) {
$wwwauth .= 'nextnonce="'.$this->nextNonce.'", ';
}
$wwwauth .= 'qop='.$this->auth['qop'].', ';
$wwwauth .= 'rspauth="'.md5($combined).'", ';
$wwwauth .= 'cnonce="'.$this->auth['cnonce'].'", ';
$wwwauth .= 'nc='.$this->auth['nc'].'';
header($wwwauth);
}
}
// }}}
// {{{ setOption()
/**
* set authentication option
*
* @access public
* @param mixed $name key of option
* @param mixed $value value of option
* @return void
*/
function setOption($name, $value = null)
{
if (is_array($name)) {
foreach($name as $key => $value) {
if (array_key_exists( $key, $this->options)) {
$this->options[$key] = $value;
}
}
} else {
if (array_key_exists( $name, $this->options)) {
$this->options[$name] = $value;
}
}
}
// }}}
// {{{ getOption()
/**
* get authentication option
*
* @access public
* @param string $name key of option
* @return mixed option value
*/
function getOption($name)
{
if (array_key_exists( $name, $this->options)) {
return $this->options[$name];
}
if ($name == 'CancelText') {
return $this->CancelText;
}
if ($name == 'Realm') {
return $this->realm;
}
return false;
}
// }}}
// {{{ selfURI()
/**
* get self URI
*
* @access public
* @return string self URI
*/
function selfURI()
{
if (method_exists($this, '_importGlobalVariable')) {
$this->server = &$this->_importGlobalVariable('server');
}
if (preg_match("/MSIE/",$this->server['HTTP_USER_AGENT'])) {
// query string should be removed for MSIE
$uri = preg_replace("/^(.*)\?/","\\1",$this->server['REQUEST_URI']);
} else {
$uri = $this->server['REQUEST_URI'];
}
return $uri;
}
// }}}
}
// }}}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
*/
?>
Auth_HTTP-2.1.8/docs/sample.sql 0000664 0001750 0001750 00000001332 11711007357 014377 0 ustar rui rui -- SQLite schema for permission administration
-- usage: sqlite /tmp/user.db < sample.sql
CREATE TABLE auth (
username VARCHAR(50) NOT NULL, -- username
password VARCHAR(50) NOT NULL -- password
);
-- plain password
--INSERT INTO auth VALUES ('taro','secret');
--INSERT INTO auth VALUES ('jiro','secret');
-- md5 hash password: secret
--INSERT INTO auth VALUES ('taro','5ebe2294ecd0e0f08eab7690d2a6ee69');
--INSERT INTO auth VALUES ('jiro','5ebe2294ecd0e0f08eab7690d2a6ee69');
-- a1 (md5(username:realm:password)) for http digest authentication
-- realm: sample, password: secret
INSERT INTO auth VALUES ('taro','d0f7c5ba4f2f2ed16f2a714332633ad5');
INSERT INTO auth VALUES ('jiro','d41438d297ee671f2249cc0d6c1f3997');
Auth_HTTP-2.1.8/docs/test_basic_simple.php 0000664 0001750 0001750 00000001116 11711007357 016577 0 ustar rui rui DSN);
$auth = new Auth_HTTP("DB", $options);
$auth->setRealm('dummy', 'sample');
$auth->start();
?>
HTTP Basic authentication test for simple case
authType."
";
print "username: ".$auth->username."
";
print "password: ".$auth->password."
";
print "auth: ".print_r($auth->auth)."
";
if($auth->getAuth()) {
print "authentication is succeeded.
";
}
?>
Auth_HTTP-2.1.8/docs/test_digest_get.php 0000664 0001750 0001750 00000001414 11711007357 016264 0 ustar rui rui DSN, 'authType'=>'digest');
$auth = new Auth_HTTP("DB", $options);
$auth->setRealm('dummy', 'sample');
$auth->start();
?>
HTTP digest authentication for GET method
authMethod."
";
print "username: ".$auth->username."
";
print "password: ".$auth->password."
";
print "auth: ".print_r($auth->auth)."
";
if($auth->getAuth()) {
print <<
EOS;
}
if (!empty($_POST['title'])) {echo 'Title: '.$_POST['title'];}
?>
Auth_HTTP-2.1.8/docs/test_digest_post.php 0000664 0001750 0001750 00000001333 11711007357 016472 0 ustar rui rui DSN, 'authType'=>'digest');
$auth = new Auth_HTTP("DB", $options);
$auth->setRealm('dummy', 'sample');
$auth->start();
?>
HTTP digest authentication for POST method
getAuth()) {
print <<
EOS;
}
if (!empty($_POST['title'])) {echo 'POST:Title: '.$_POST['title'].'
';}
if (!empty($_GET['foo'])) {echo 'GET:foo: '.$_GET['foo'].'
';}
print "METHOD: ".$_SERVER['REQUEST_METHOD']."
";
?>
Auth_HTTP-2.1.8/docs/test_digest_simple.php 0000664 0001750 0001750 00000001145 11711007357 016777 0 ustar rui rui DSN, 'authType'=>'digest');
$auth = new Auth_HTTP("DB", $options);
$auth->setRealm('dummy', 'sample');
$auth->start();
?>
HTTP digest authentication test for simple case
authType."
";
print "username: ".$auth->username."
";
print "password: ".$auth->password."
";
print "auth: ".print_r($auth->auth)."
";
if($auth->getAuth()) {
print "authentication is succeeded.
";
}
?>
Auth_HTTP-2.1.8/README 0000664 0001750 0001750 00000001020 11711007357 012317 0 ustar rui rui This package is http://pear.php.net/package/Auth_HTTP and has been migrated from https://svn.php.net/repository/pear/packages/Auth_HTTP
Please report all new issues via the PEAR bug tracker.
If this package is marked as unmaintained and you have fixes, please submit your pull requests and start discussion on the pear-qa mailing list.
To test, run either
$ phpunit tests/
or
$ pear run-tests -r
To build, simply
$ pear package
To install from scratch
$ pear install package.xml
To upgrade
$ pear upgrade -f package.xml