Location: PHPKode > projects > iF.SVNAdmin > svnadmin/ifphplib/IF_SVNAuthFileC.class.php
<?php
/**
 * iF.SVNAdmin
 * Copyright (c) 2010 by Manuel Freiholz
 * http://www.insanefactory.com/
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; version 2
 * of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.
 */
/**
 * This class provides functionality to manage the SVNAuthFile.
 * Managing group and user rights for repositories.
 *
 * <p><b>Note:</b> This class does not manage user Accounts.
 *
 * @author Manuel Freiholz (Gainwar)
 * @since 08/02/2009
 * @copyright insaneFactory.com
 * @require inifile.func.php
 */
class IF_SVNAuthFileC
{
	public $GROUP_SIGN = "@";
	public $GROUP_SECTION = "groups";
  public $ALIAS_SECTION = "alias";
  
  public static $PERMISSION_NONE = "";
  public static $PERMISSION_READ = "r";
  public static $PERMISSION_READWRITE = "rw";

  private $m_authfile = NULL;
  private $m_errno = 0;
  public $m_data = array();

  /**
   *
   * @return unknown_type
   */
  public function __construct()
  {
  }

  /**
   * Returns the error number, if any error occured.
   *
   * @return int
   */
  public function errno()
  {
    return $this->m_errno;
  }

  /**
   * Gets the error definition string according to the error number.
   *
   * @return string
   */
  public function error()
  {
  	switch($this->m_errno)
  	{
  		case 100: return "The file does not exists.";
  		case 101: return "No permission to read the file content.";
  		case 102: return "Could not read file contents from file.";
  		case 110: return "Error during parsing file.";
  		case 120: return "The repository path is already configured.";
  		case 121: return "Invalid access path syntax. (Right: <reponame>:/<accesspath>)";
  		case 123: return "The repository path is not configured.";
  		case 130: return "Could not save file to disk.";
  		case 140: return "No groups section defined.";
  		case 141: return "The group already exists.";
  		case 142: return "The group does not exist.";
  		case 143: return "Invalid group name. (A-Z, 0-9, -, _)";
  		case 144: return "The user is already in group.";
  		case 145: return "The user is not in group.";

  		case 0: return "No error.";
  		case 1: return "Unknown error.";
  		default: return "Unknown error";
  	}
  	return NULL;
  }

  /**
   * open the given SVNAuthFile, which contains permissions
   * of the svn users/groups.
   *
   * @param $authfile Path to the SVNAuthFile
   * @return bool
   */
  public function open( $authfile )
  {
  	$this->m_authfile = $authfile;
    if( !file_exists($authfile) )
    {
      $this->m_errno = 100;
      return false;
    }

    if( !is_readable($authfile) )
    {
    	$this->m_errno = 101;
    	return false;
    }

    // load file contents into the local member variable.
    //$fileContent = file_get_contents($authfile);
    //if( $fileContent == false )
    //{
    //  $this->m_errno = 102;
    //  return false;
    //}

    // parse file.
    $this->m_data = if_parse_ini_file($authfile);
    if( $this->m_data == false )
    {
      //$this->m_errno = 110;
      //return false;
    }

    // everything works OK.
    return true;
  }

  /**
   * Writes the changed authfile to the given destination file. If $dest is
   * NULL then it will be written to the same file from which the data has
   * been read.
   *
   * @param string $dest
   * @return bool
   */
  public function save( $dest = NULL )
  {
  	if( $dest == NULL )
  	{
  		$dest = $this->m_authfile;
  	}

  	// write data to file.
  	$flag = if_write_ini_file( $dest, $this->m_data );
  	if( !$flag )
  	{
  		$this->m_errno = 130;
      return false;
  	}
    return true;
  }

  /**
   * Gets all configured groups.
   *
   * @return array Filled with group names or FALSE if the section "groups" doesn't exists.
   */
  public function &groups()
  {
  	$ret = array();

  	// assoc array "groupname=>users".
  	$groups =& $this->m_data[$this->GROUP_SECTION];

    if( is_array($groups) )
    {
	  	foreach( $groups as $k=>&$v )
	  	{
	  		array_push($ret, $k);
	  	}
    }
    else
    {
    	// the section does not exists.
    	$this->m_errno = 140;
    	return $ret;
    }

  	return $ret;
  }

  /**
   * Gets all configured repositories.
   *
   * @return array<string>
   */
  public function &repositories()
  {
  	$ret = array();

  	// assoc array "section=>key=>value".
  	// get all section names, but not the section with name "groups".
  	foreach( $this->m_data as $sec=>&$v )
  	{
      if( $sec != $this->GROUP_SECTION && $sec != $this->ALIAS_SECTION )
      {
      	array_push($ret, $sec);
      }
  	}

  	return $ret;
  }

  /**
   * Gets all users of the given group.
   *
   * @param string $group
   * @return array with string's of users or FALSE on error.
   */
  public function &usersOfGroup( &$group )
  {
  	$ret = array();

    // get group section array.
    $groups =& $this->m_data[$this->GROUP_SECTION];

    if( !is_array($groups) )
    {
    	// the group section does not exist.
    	$this->m_errno = 140;
    	return false;
    }

    // search for group.
    $users = NULL;
    foreach( $groups as $grpname=>&$v )
    {
      if( $grpname == $group )
      {
      	$users =& $v;
      	break;
      }
    }

    if( !empty($users) )
    {
    	$ret = explode(",",$users);

    	for( $i=0; $i<count($ret); $i++ )
    	{
    		$ret[$i] = trim($ret[$i]);
    	}
    }

    return $ret;
  }

  /**
   * Gets all users which have direct rights to this repository path.
   *
   * @param $repo
   * @return array with string's of users.
   */
  public function &usersOfRepository( &$repo )
  {
  	$ret = array();

  	// get the keys of the wished section.
  	$keys =& $this->m_data[$repo];

  	if( is_array($keys) )
  	{
  		// iterate the array and collect all users. (skip groups)
  		// $k = username
  		// $v = permission
  		foreach( $keys as $k=>&$v )
  		{
  			$pos = strpos($k,$this->GROUP_SIGN);
  			if( $pos === false )
  			{
          $data = array();
          $data[0] = $k; // pass by value
          $data[1] = $v; // pass by value
          
  			  // its a user.
  			  array_push($ret,$data);
  			}
  			else
  			{
  				// its a group.
  				continue;
  			}
  		}
  	}
  	return $ret;
  }

  /**
   * Gets all groups which have direct rights to this repository path.
   *
   * @param $repo
   * @return array with string's of groups.
   */
  public function &groupsOfRepository( &$repo )
  {
    $ret = array();

    // get the keys of the wished section.
    $keys =& $this->m_data[$repo];

    if( is_array($keys) )
    {
      // iterate the array and collect all groups. (skip users)
      foreach( $keys as $k=>&$v )
      {
        $pos = strpos($k,$this->GROUP_SIGN);
        if( $pos === false )
        {
          // its a user.
          continue;
        }
        else
        {
          $data = array();
          $data[0] = substr($k,1);
          $data[1] = $v;
        
          // its a group.
          array_push($ret,$data);
        }
      }
    }
    return $ret;
  }

  /**
   * Gets all groups of which the user is a member.
   *
   * @param $username
   * @return unknown_type
   */
  public function &groupsOfUser( &$username )
  {
    $groups =& $this->groups();
    $grpList = array();

    if( !is_array( $groups ) )
    {
    	return $grpList;
    }

    // Iterate all groups and check whether the user is a member of it.
    foreach( $groups as &$g )
    {
    	$users =& $this->usersOfGroup( $g );
    	if( in_array( $username, $users ) )
    	{
    		array_push( $grpList, $g );
    	}
    }

    return $grpList;
  }
  
  /**
   * Gets all repository paths which have the group associated.
   *
   * @param string $groupname
   * @return array<string> List of repository paths
   */
  public function &repositoryPathsOfGroup( &$groupname )
  {
    $grpname = $this->GROUP_SIGN.$groupname;
    
    // List of repo paths.
    $list = array();
  
    // Iterate all repositories and search for the groupname.
    foreach( $this->m_data as $sec=>&$v )
    {
      // Iterate all groups and users of the current repository path iteration.
      foreach( $v as $name=>&$notneeded )
      {
        // Check whether the current $name is the groupname.
        if( $name == $grpname )
        {
          // Yes it is, add the repository path to the return list and abort searching for more inside of this repo.
          array_push( $list, $sec );
          break;
        }
      }
    }
    return $list;
  }
  
  /**
   * Gets all repository paths which have the user associated.
   *
   * @param string $username
   * @return array<string> List of repository paths
   */
  public function &repositoryPathsOfUser( &$username )
  {
    // List of repo paths.
    $list = array();

    // Iterate all repositories and search for the username.
    foreach( $this->m_data as $sec=>&$v )
    {
      // Iterate all groups and users of the current repository path iteration.
      foreach( $v as $name=>&$notneeded )
      {
        // Check whether the current $name is the groupname.
        if( $name == $username )
        {
          // Yes it is, add the repository path to the return list and abort searching for more inside of this repo.
          array_push( $list, $sec );
          break;
        }
      }
    }
    return $list;
  }

  /**
   * Checks whether the repository path already exists in the configuration.
   *
   * @param string $repopath the repository path
   * @return bool true/false
   */
  public function repositoryPathExists( &$repopath )
  {
    // assoc array "section=>key=>value".
    // get all section names, but not the section with name "groups".
    foreach( $this->m_data as $sec=>&$v )
    {
      if( $sec == $repopath )
      {
        return true;
      }
    }
    return false;
  }

  /**
   * Adds a new repostory configuration path to the SVNAuthFile.
   *
   * @param string $repopath
   * @return bool true/false
   */
  public function addRepositoryPath( &$repopath )
  {
    if( self::repositoryPathExists( $repopath ) )
    {
    	$this->m_errno = 120;
    	return false;
    }

    // Validate the $repopath string.
    $pattern = '/^[A-Za-z0-9\_\-]+:\/.*$/i';
    if( $repopath != "/" && !preg_match( $pattern, $repopath ) )
    {
    	$this->m_errno = 121;
    	return false;
    }

    // Create the repository configuration path.
    $this->m_data[$repopath] = array();
    return true;
  }

  /**
   * Removes the access path from the configuration.
   * @param $repopath
   * @return unknown_type
   */
  public function removeRepositoryPath( &$repopath )
  {
    if( !self::repositoryPathExists( $repopath ) )
    {
      $this->m_errno = 123; // The repository path does not exist.
      return false;
    }

    // Remove item from array.
    unset( $this->m_data[$repopath] );
    return true;
  }

  /**
   * Checks whether the group "$groupname" already exists.
   * @param $groupname
   * @return bool
   */
  public function groupExists( &$groupname )
  {
  	// Get the groups array.
  	$groups =& $this->m_data[$this->GROUP_SECTION];

  	if( !is_array($groups) )
  	{
  		// No groups defined.
  		$this->m_errno = 140;
  		return false;
  	}

  	if( isset( $groups[$groupname] ) )
  	{
  		return true;
  	}
  	return false;
  }

  /**
   * Creates the new group "$groupname", if it does not exist.
   * @param string $groupname
   * @return bool TRUE/FALSE
   */
  public function createGroup( &$groupname )
  {
  	// Validate the groupname.
  	$pattern = '/^[A-Za-z0-9\-\_]+$/i';
  	if( !preg_match( $pattern, $groupname ) )
  	{
  		$this->m_errno = 143;
  		return false;
  	}

  	if( self::groupExists( $groupname ) )
  	{
  		$this->m_errno = 141;
  		return false;
  	}

  	// Get the groups array and add the new group to it.
  	$this->m_data[$this->GROUP_SECTION][$groupname] = "";
  	return true;
  }

  /**
   * Deletes the given group by name.
   * @param $groupname
   * @return bool
   */
  public function deleteGroup( &$groupname )
  {
  	if( !self::groupExists( $groupname ) )
  	{
  		$this->m_errno = 142;
  		return false;
  	}

  	// Delete the group now.
  	unset( $this->m_data[$this->GROUP_SECTION][$groupname] );
    return true;
  }

  /**
   * Adds the user to group.
   * @param $groupname
   * @param $username
   * @return unknown_type
   */
  public function addUserToGroup( &$groupname, &$username )
  {
    if( !self::groupExists( $groupname ) )
    {
      $this->m_errno = 142;
      return false;
    }

    // Get current users.
    $users =& $this->usersOfGroup( $groupname );
    if( !is_array($users) )
    {
      return false;
    }

    // NOTE: Its no longer an error when the user is already in group!!!
    // Check whether the user is already in group.
    if( in_array( $username, $users ) )
    {
      //$this->m_errno = 144;
      //return false;
      return true;
    }

    // Add user to $users array.
    array_push( $users, $username );

    // Set the array as new value of group.
    $this->m_data[$this->GROUP_SECTION][$groupname] = join(",", $users);
    return true;
  }

  /**
   * Checks whether the user is in the given group.
   *
   * @param $groupname
   * @param $username
   * @return unknown_type
   */
  public function isUserInGroup( &$groupname, &$username )
  {
  	$users =& $this->usersOfGroup( $groupname );

  	if( !is_array( $users ) )
  	{
  		return false;
  	}

  	foreach( $users as &$usr )
  	{
  		if( $usr == $username )
  		{
  			return true;
  		}
  	}
  	return false;
  }

  /**
   * Removes the given user from group.
   *
   * @param $username
   * @param $groupname
   * @return bool
   */
  public function removeUserFromGroup( &$username, &$groupname )
  {
    $groupUsers =& $this->usersOfGroup( $groupname );
    if( !is_array( $groupUsers ) )
    {
    	return false;
    }

    // Search the user in array.
    $pos = array_search( $username, $groupUsers );

    if( $pos !== FALSE )
    {
    	// Remove the user from array.
    	unset( $groupUsers[$pos] );

    	$userString = join( ",", $groupUsers );
    	$this->m_data[$this->GROUP_SECTION][$groupname] = $userString;
    }
    else
    {
    	// User is not in group.
    	$this->m_errno = 145;
    	return true;
    }
    return true;
  }
  
  /**
   * Removes the given $groupname from $repository.
   * @param $groupname string
   * @param $repository string
   * @return bool
   */
  public function removeGroupFromRepository( &$groupname, &$repository )
  {
    // Does the repo config exists?
    if( !isset( $this->m_data[$repository] ) )
    {
      $this->m_errno = 123;
      return false;
    }
    
    // The repository section array.
    $sec =& $this->m_data[$repository];
    
    // k = user or group name
    // v = the assigned right
    foreach( $sec as $k=>&$v )
    {
      // Find out whether the current key is a groupname.
      $pos = strpos( $k, $this->GROUP_SIGN );
      if( $pos !== FALSE )
      {
        $grp = substr( $k, 1 );
        if( $grp == $groupname )
        {
          // Remove group from repository.
          unset( $this->m_data[$repository][$k] );
          return TRUE;
        }
      }
    }
    return TRUE;
  }
  
  /**
   * Removes the given $groupname from $repository.
   * @param $groupname string
   * @param $repository string
   * @return bool
   */
  public function removeUserFromRepository( &$username, &$repository )
  {
    // Does the repo config exists?
    if( !isset( $this->m_data[$repository] ) )
    {
      $this->m_errno = 123;
      return false;
    }

    // The repository section array.
    $sec =& $this->m_data[$repository];

    // k = user or group name
    // v = the assigned right
    foreach( $sec as $k=>&$v )
    {
      // Find out whether the current key is a username.
      $pos = strpos( $k, $this->GROUP_SIGN );
      if( $pos === FALSE )
      {
        $usr = &$k;
        if( $usr == $username )
        {
          // Remove user from repository.
          unset( $this->m_data[$repository][$k] );
          return TRUE;
        }
      }
    }
    return TRUE;
  }
  
  public function isUserAssignedToRepository( &$username, &$repository, &$permission = NULL )
  {
    // Does the repo exists?
    if( !isset( $this->m_data[$repository] ) )
    {
      $this->m_errno = 123;
      return false;
    }
    
    // The repository section array.
    $sec =& $this->m_data[$repository];

    // k = user or group name
    // v = the assigned right
    foreach( $sec as $k=>&$v )
    {
      if( $k == $username )
      {
        if( $permission == NULL )
        {
          return true;
        }
        else
        {
          if( $v == $permission )
          {
            return true;
          }
          else
          {
            return false;
          }
        }
      }
    }
  }
  
  public function addUserToRepository( &$username, &$repository, &$permission )
  {
    // Does the repo exists?
    if( !isset( $this->m_data[$repository] ) )
    {
      $this->m_errno = 123;
      return false;
    }
    
    // The repository section array.
    $sec =& $this->m_data[$repository];
    $sec[$username] = $permission;
    
    return true;
  }
  
  public function addGroupToRepository( &$groupname, &$repository, &$permission )
  {
    // Does the repo exists?
    if( !isset( $this->m_data[$repository] ) )
    {
      $this->m_errno = 123;
      return false;
    }
    
    // The repository section array.
    $sec =& $this->m_data[$repository];
    $sec[$this->GROUP_SIGN.$groupname] = $permission;
    
    return true;
  }
  
  public function &permissionsOfUser( $username )
  {
    $ret = array();
    
    // Iterate all access paths.
    foreach( $this->m_data as $repo_name=>&$v )
    {
      if( $repo_name == $this->GROUP_SECTION )
      { continue; }
      
      // Iterate the user/group names of the current repository.
      foreach( $v as $usergroup_name=>&$val )
      {
        // User or group name?
        if( substr( $usergroup_name, 0, 1 ) == $this->GROUP_SIGN ) // $usergroup_name is a group name.
        {
          $grpname = substr( $usergroup_name, 1 );
          if( self::isUserInGroup($grpname, $username) )
          {
            $data = array();
            $data[0] = $repo_name;  // access-path
            $data[1] = $val;        // permission
            $data[2] = $grpname;    // group name from which the user owns the rights.
            array_push( $ret, $data );
          }
        }
        elseif( $usergroup_name == '*' && $username != '*' )
        {
          $data = array();
          $data[0] = $repo_name;
          $data[1] = $val;
          $data[2] = '*';
          array_push( $ret, $data );
        }
        else // $usergroup_name is a user name.
        {
          $usrname = $usergroup_name;
          if( $usrname == $username )
          {
            $data = array();
            $data[0] = $repo_name;
            $data[1] = $val;
            $data[2] = '';        // empty string, cause its a direct permission.
            array_push( $ret, $data );
          }
        }
      }
    }
    return $ret;
  }

  public function &permissionsOfGroup( $groupname )
  {
    $ret = array();
  
    $internal_groupname = $this->GROUP_SIGN . $groupname;
  
    // Iterate all repos and search for the given groupname.
    foreach( $this->m_data as $repo_name=>&$v )
    {
      if( $repo_name == $this->GROUP_SECTION )
      {
        continue;
      }
      
      // Iterate the user/group names of the current repository.
      foreach( $v as $group_name=>&$val )
      {
        if( $group_name == $internal_groupname )
        {
          $data = array();
          $data[0] = $repo_name;
          $data[1] = $val;
          
          array_push( $ret, $data );
        }
      }
    }//foreach
    return $ret;
  }
  
  /**
   * Gets all rights recursive up including groups, which have
   * access to the given repository $path.
   * 
   * Returns an array of users with associated inheritance. (from group or * user.)
   * 
   * @param $path string
   * @return array<$username => array<"from" => "grpname", "perm" => "r">>
   */
  function getAssignmentsOfPath($path)
  {
  	// TODO: Implement getAssignmentsOfPath()
  }
}
?>
Return current item: iF.SVNAdmin