| <?php␊ | 
| /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4: */␊ | 
| ␊ | 
| /**␊ | 
| * File::Passwd::Authbasic␊ | 
| * ␊ | 
| * PHP versions 4 and 5␊ | 
| *␊ | 
| * LICENSE: This source file is subject to version 3.0 of the PHP license␊ | 
| * that is available through the world-wide-web at the following URI:␊ | 
| * http://www.php.net/license/3_0.txt.  If you did not receive a copy of␊ | 
| * the PHP License and are unable to obtain it through the web, please␊ | 
| * send a note to license@php.net so we can mail you a copy immediately.␊ | 
| *␊ | 
| * @category   FileFormats␊ | 
| * @package    File_Passwd␊ | 
| * @author     Michael Wallner <mike@php.net>␊ | 
| * @copyright  2003-2005 Michael Wallner␊ | 
| * @license    http://www.php.net/license/3_0.txt  PHP License 3.0␊ | 
| * @version    CVS: $Id: Authbasic.php,v 1.17 2005/03/30 18:33:33 mike Exp $␊ | 
| * @link       http://pear.php.net/package/File_Passwd␊ | 
| */␊ | 
| ␊ | 
| /**␊ | 
| * Requires File::Passwd::Common␊ | 
| */␊ | 
| require_once 'File/Passwd/Common.php';␊ | 
| ␊ | 
| /**␊ | 
| * Manipulate AuthUserFiles as used for HTTP Basic Authentication.␊ | 
| *␊ | 
| * <kbd><u>␊ | 
| *   Usage Example:␊ | 
| * </u></kbd>␊ | 
| * <code>␊ | 
| *   $htp = &File_Passwd::factory('AuthBasic');␊ | 
| *   $htp->setMode('sha');␊ | 
| *   $htp->setFile('/www/mike/auth/.htpasswd');␊ | 
| *   $htp->load();␊ | 
| *   $htp->addUser('mike', 'secret');␊ | 
| *   $htp->save();␊ | 
| * </code>␊ | 
| * ␊ | 
| * <kbd><u>␊ | 
| *   Output of listUser()␊ | 
| * </u></kbd>␊ | 
| * <pre>␊ | 
| *      array␊ | 
| *       + user => crypted_passwd␊ | 
| *       + user => crypted_passwd␊ | 
| * </pre>␊ | 
| * ␊ | 
| * @author   Michael Wallner <mike@php.net>␊ | 
| * @package  File_Passwd␊ | 
| * @version  $Revision: 1.17 $␊ | 
| * @access   public␊ | 
| */␊ | 
| class File_Passwd_Authbasic extends File_Passwd_Common␊ | 
| {␊ | 
| /** ␊ | 
| * Path to AuthUserFile␊ | 
| *␊ | 
| * @var string␊ | 
| * @access private␊ | 
| */␊ | 
| var $_file = '.htpasswd';␊ | 
| ␊ | 
| /** ␊ | 
| * Actual encryption mode␊ | 
| *␊ | 
| * @var string␊ | 
| * @access private␊ | 
| */␊ | 
| var $_mode = 'sha';␊ | 
| ␊ | 
| /** ␊ | 
| * Supported encryption modes␊ | 
| *␊ | 
| * @var array␊ | 
| * @access private␊ | 
| */␊ | 
| var $_modes = array('plain' => 'p', 'md5' => 'm', 'des' => 'd', 'sha' => 's');␊ | 
| ␊ | 
| /** ␊ | 
| * Constructor␊ | 
| * ␊ | 
| * @access public␊ | 
| * @param  string $file   path to AuthUserFile␊ | 
| */␊ | 
| function File_Passwd_Authbasic($file = '.htpasswd')␊ | 
| {␊ | 
| File_Passwd_Authbasic::__construct($file);␊ | 
| }␊ | 
| ␊ | 
| /**␊ | 
| * Constructor (ZE2)␊ | 
| * ␊ | 
| * Rewritten because DES encryption is not ␊ | 
| * supportet by the Win32 httpd.␊ | 
| * ␊ | 
| * @access protected␊ | 
| * @param  string $file   path to AuthUserFile␊ | 
| */␊ | 
| function __construct($file = '.htpasswd')␊ | 
| {␊ | 
| if (strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') {␊ | 
| unset($this->_modes['des']);␊ | 
| }␊ | 
| $this->setFile($file);␊ | 
| }␊ | 
| ␊ | 
| /**␊ | 
| * Fast authentication of a certain user␊ | 
| * ␊ | 
| * Returns a PEAR_Error if:␊ | 
| *   o file doesn't exist␊ | 
| *   o file couldn't be opened in read mode␊ | 
| *   o file couldn't be locked exclusively␊ | 
| *   o file couldn't be unlocked (only if auth fails)␊ | 
| *   o file couldn't be closed (only if auth fails)␊ | 
| *␊ | 
| * @static   call this method statically for a reasonable fast authentication␊ | 
| * ␊ | 
| * @throws   PEAR_Error␊ | 
| * @access   public␊ | 
| * @return   mixed   true if authenticated, false if not or PEAR_Error␊ | 
| * @param    string  $file   path to passwd file␊ | 
| * @param    string  $user   user to authenticate␊ | 
| * @param    string  $pass   plaintext password␊ | 
| * @param    string  $mode   des, sha or md5␊ | 
| */␊ | 
| function staticAuth($file, $user, $pass, $mode)␊ | 
| {␊ | 
| $line = File_Passwd_Common::_auth($file, $user);␊ | 
| if (!$line || PEAR::isError($line)) {␊ | 
| return $line;␊ | 
| }␊ | 
| list(,$real)    = explode(':', $line);␊ | 
| $crypted        = File_Passwd_Authbasic::_genPass($pass, $real, $mode);␊ | 
| if (PEAR::isError($crypted)) {␊ | 
| return $crypted;␊ | 
| }␊ | 
| return ($real === $crypted);␊ | 
| }␊ | 
| ␊ | 
| /** ␊ | 
| * Apply changes and rewrite AuthUserFile␊ | 
| *␊ | 
| * Returns a PEAR_Error if:␊ | 
| *   o directory in which the file should reside couldn't be created␊ | 
| *   o file couldn't be opened in write mode␊ | 
| *   o file couldn't be locked exclusively␊ | 
| *   o file couldn't be unlocked␊ | 
| *   o file couldn't be closed␊ | 
| * ␊ | 
| * @throws PEAR_Error␊ | 
| * @access public␊ | 
| * @return mixed true on success or PEAR_Error␊ | 
| */␊ | 
| function save()␊ | 
| {␊ | 
| $content = '';␊ | 
| foreach ($this->_users as $user => $pass) {␊ | 
| $content .= $user . ':' . $pass . "\n";␊ | 
| }␊ | 
| return $this->_save($content);␊ | 
| }␊ | 
| ␊ | 
| /** ␊ | 
| * Add an user␊ | 
| *␊ | 
| * The username must start with an alphabetical character and must NOT␊ | 
| * contain any other characters than alphanumerics, the underline and dash.␊ | 
| * ␊ | 
| * Returns a PEAR_Error if:␊ | 
| *   o user already exists␊ | 
| *   o user contains illegal characters␊ | 
| * ␊ | 
| * @throws PEAR_Error␊ | 
| * @access public␊ | 
| * @return mixed true on success or PEAR_Error␊ | 
| * @param string $user␊ | 
| * @param string $pass␊ | 
| */␊ | 
| function addUser($user, $pass)␊ | 
| {␊ | 
| if ($this->userExists($user)) {␊ | 
| return PEAR::raiseError(␊ | 
| sprintf(FILE_PASSWD_E_EXISTS_ALREADY_STR, 'User ', $user),␊ | 
| FILE_PASSWD_E_EXISTS_ALREADY␊ | 
| );␊ | 
| }␊ | 
| if (!preg_match($this->_pcre, $user)) {␊ | 
| return PEAR::raiseError(␊ | 
| sprintf(FILE_PASSWD_E_INVALID_CHARS_STR, 'User ', $user),␊ | 
| FILE_PASSWD_E_INVALID_CHARS␊ | 
| );␊ | 
| }␊ | 
| $this->_users[$user] = $this->_genPass($pass);␊ | 
| return true;␊ | 
| }␊ | 
| ␊ | 
| /** ␊ | 
| * Change the password of a certain user␊ | 
| *␊ | 
| * Returns a PEAR_Error if user doesn't exist.␊ | 
| * ␊ | 
| * @throws PEAR_Error␊ | 
| * @access public␊ | 
| * @return mixed true on success or a PEAR_Error␊ | 
| * @param string $user   the user whose password should be changed␊ | 
| * @param string $pass   the new plaintext password␊ | 
| */␊ | 
| function changePasswd($user, $pass)␊ | 
| {␊ | 
| if (!$this->userExists($user)) {␊ | 
| return PEAR::raiseError(␊ | 
| sprintf(FILE_PASSWD_E_EXISTS_NOT_STR, 'User ', $user),␊ | 
| FILE_PASSWD_E_EXISTS_NOT␊ | 
| );␊ | 
| }␊ | 
| $this->_users[$user] = $this->_genPass($pass);␊ | 
| return true;␊ | 
| }␊ | 
| ␊ | 
| /** ␊ | 
| * Verify password␊ | 
| *␊ | 
| * Returns a PEAR_Error if:␊ | 
| *   o user doesn't exist␊ | 
| *   o an invalid encryption mode was supplied␊ | 
| * ␊ | 
| * @throws PEAR_Error␊ | 
| * @access public␊ | 
| * @return mixed true if passwords equal, false if they don't, or PEAR_Error␊ | 
| * @param string $user   the user whose password should be verified␊ | 
| * @param string $pass   the plaintext password to verify␊ | 
| */␊ | 
| function verifyPasswd($user, $pass)␊ | 
| {␊ | 
| if (!$this->userExists($user)) {␊ | 
| return PEAR::raiseError(␊ | 
| sprintf(FILE_PASSWD_E_EXISTS_NOT_STR, 'User ', $user),␊ | 
| FILE_PASSWD_E_EXISTS_NOT␊ | 
| );␊ | 
| }␊ | 
| $real = $this->_users[$user];␊ | 
| return ($real === $this->_genPass($pass, $real));␊ | 
| }␊ | 
| ␊ | 
| /** ␊ | 
| * Get actual encryption mode␊ | 
| *␊ | 
| * @access public␊ | 
| * @return string␊ | 
| */␊ | 
| function getMode()␊ | 
| {␊ | 
| return $this->_mode;␊ | 
| }␊ | 
| ␊ | 
| /** ␊ | 
| * Get supported encryption modes␊ | 
| *␊ | 
| * <pre>␊ | 
| *   array␊ | 
| *    + md5␊ | 
| *    + sha␊ | 
| *    + des␊ | 
| * </pre>␊ | 
| * ␊ | 
| * ATTN: DES encryption not available on Win32!␊ | 
| * ␊ | 
| * @access public␊ | 
| * @return array␊ | 
| */␊ | 
| function listModes()␊ | 
| {␊ | 
| return array_keys($this->_modes);␊ | 
| }␊ | 
| ␊ | 
| /** ␊ | 
| * Set the encryption mode␊ | 
| *␊ | 
| * You can choose one of md5, sha or des.␊ | 
| * ␊ | 
| * ATTN: DES encryption not available on Win32!␊ | 
| * ␊ | 
| * Returns a PEAR_Error if a specific encryption mode is not supported.␊ | 
| * ␊ | 
| * @throws PEAR_Error␊ | 
| * @access public␊ | 
| * @return mixed true on succes or PEAR_Error␊ | 
| * @param string $mode␊ | 
| */␊ | 
| function setMode($mode)␊ | 
| {␊ | 
| $mode = strToLower($mode);␊ | 
| if (!isset($this->_modes[$mode])) {␊ | 
| return PEAR::raiseError(␊ | 
| sprintf(FILE_PASSWD_E_INVALID_ENC_MODE_STR, $this->_mode),␊ | 
| FILE_PASSWD_E_INVALID_ENC_MODE␊ | 
| );␊ | 
| }␊ | 
| $this->_mode = $mode;␊ | 
| return true;␊ | 
| }␊ | 
| ␊ | 
| /**␊ | 
| * Generate password with htpasswd executable␊ | 
| * ␊ | 
| * @access   private␊ | 
| * @return   string  the crypted password␊ | 
| * @param    string  $pass   the plaintext password␊ | 
| * @param    string  $salt   the salt to use␊ | 
| * @param    string  $mode   encyption mode, usually determined from␊ | 
| *                           <var>$this->_mode</var>␊ | 
| */␊ | 
| function _genPass($pass, $salt = null, $mode = null)␊ | 
| {␊ | 
| $mode = is_null($mode) ? strToLower($this->_mode) : strToLower($mode);␊ | 
| ␊ | 
| if ($mode == 'md5') {␊ | 
| return File_Passwd::crypt_apr_md5($pass, $salt);␊ | 
| } elseif ($mode == 'des') {␊ | 
| return File_Passwd::crypt_des($pass, $salt);␊ | 
| } elseif ($mode == 'sha') {␊ | 
| return File_Passwd::crypt_sha($pass, $salt);␊ | 
| } else if ($mode == 'plain') {␊ | 
| return $pass;␊ | 
| ␉}␊ | 
| ␊ | 
| return PEAR::raiseError(␊ | 
| sprintf(FILE_PASSWD_E_INVALID_ENC_MODE_STR, $mode),␊ | 
| FILE_PASSWD_E_INVALID_ENC_MODE                ␊ | 
| );␊ | 
| }␊ | 
| ␊ | 
| /** ␊ | 
| * Parse the AuthUserFile␊ | 
| * ␊ | 
| * Returns a PEAR_Error if AuthUserFile has invalid format.␊ | 
| *␊ | 
| * @throws PEAR_Error␊ | 
| * @access public␊ | 
| * @return mixed true on success or PEAR_error␊ | 
| */␊ | 
| function parse()␊ | 
| {␊ | 
| $this->_users = array();␊ | 
| foreach ($this->_contents as $line) {␊ | 
| $user = explode(':', $line);␊ | 
| if (count($user) != 2) {␊ | 
| return PEAR::raiseError(␊ | 
| FILE_PASSWD_E_INVALID_FORMAT_STR,␊ | 
| FILE_PASSWD_E_INVALID_FORMAT␊ | 
| );␊ | 
| }␊ | 
| $this->_users[$user[0]] = trim($user[1]);␊ | 
| }␊ | 
| $this->_contents = array();␊ | 
| return true;␊ | 
| }␊ | 
| ␊ | 
| /**␊ | 
| * Generate Password␊ | 
| * ␊ | 
| * Returns PEAR_Error FILE_PASSD_E_INVALID_ENC_MODE if the supplied␊ | 
| * encryption mode is not supported.␊ | 
| *␊ | 
| * @static␊ | 
| * @access   public␊ | 
| * @return   mixed   The crypted password on success or PEAR_Error on failure.␊ | 
| * @param    string  $pass The plaintext password.␊ | 
| * @param    string  $mode The encryption mode to use (des|md5|sha).␊ | 
| * @param    string  $salt The salt to use.␊ | 
| */␊ | 
| function generatePasswd($pass, $mode = FILE_PASSWD_DES, $salt = null)␊ | 
| {␊ | 
| if (!in_array(strToLower($mode), array('des', 'md5', 'sha'))) {␊ | 
| return PEAR::raiseError(␊ | 
| sprintf(FILE_PASSWD_E_INVALID_ENC_MODE_STR, $this->_mode),␊ | 
| FILE_PASSWD_E_INVALID_ENC_MODE                ␊ | 
| );␊ | 
| }␊ | 
| return File_Passwd_Authbasic::_genPass($pass, $salt, $mode);␊ | 
| }␊ | 
| ␊ | 
| /**␊ | 
| * @ignore␊ | 
| * @deprecated␊ | 
| */␊ | 
| function generatePassword($pass, $mode = FILE_PASSWD_DES, $salt = null)␊ | 
| {␊ | 
| return File_Passwd_Authbasic::generatePasswd($pass, $mode, $salt);␊ | 
| }␊ | 
| }␊ |