Search This Blog

Monday, May 31, 2010

Ownership and Permissions

You also can get information on file ownership and permissions. On a UNIX system like Linux, all files are associated with a specific user and a specific group of users, and assigned flags that determine who has permission to read, write, or execute their contents. Some Windows file systems and operating systems work this way, and some don't. For example, the Windows NT File System (NTFS) enables you to assign owners and permissions, while Windows 98 doesn't.


User groups are defined in UNIX so that permissions can be easily extended to a certain set of users without extending them to everyone on the system. For example, several users who are working on the same project might want to share files with each other, but with no one else.


Each of these three permissions (read, write, and execute) can be granted to (or withheld from):
  • The file owner: By default, the user whose account was used to create the file.
  • A group of users: By default, the group to which the owner belongs.
  • All users: Everyone with an account on the system
Users and groups in UNIX are identified by ID numbers as well as names. If you want to get information on a user by his ID number, you can use the posix_getpwuid() function, which returns an associative array with the following references:


Name
Description
name
The shell account username of the user
passwd
The encrypted user password
uid
The ID number of the user
gid
The group ID of the user
gecos
A Comma-separated list containing the user's full name, office phone, office number, and home phone number. On most systems, only the user's full name is available
Dir
The absolute path to the home directory of the user
shell
Absolute path to the user's default shell


Another PHP function, posix_getgrgid(), returns an associative array on a group identified by a group ID. It contains the following elements of the group structure:


Name
Description
Name
The name of the group
Gid
The ID number of the group
members
The number of members belonging to the group


You can use the following three functions to get at this information from your PHP scripts. Each takes a single argument, a filename string.
  • fileowner(): Returns the user ID of the owner of the specified file.
  • filegroup(): Returns the group ID of the owner of the specified file.
  • filetype(): Returns the type (fifo, char, dir, block, link, file, or unknown) of the specified file.
For example, you can use filetype() to check whether a given filename is a file or a directory (make sure you have a file named counter.php in the folder; create it if you need to):


<?php
//file type.php
$filename = "./counter.php";
$filegroup = filegroup($filename);
$fileowner = fileowner($filename);
$filetype = filetype($filename);

if ($filetype == 'dir') {
   echo "$filename is a directory.";
} else if ($filetype == 'file') {
   echo "$filename is a file.<br>";
} else {
   echo "$filename is neither a directory nor a file.<br>";
}

echo "It belongs to user no.$fileowner and group no.$filegroup.<br>";
echo "<br>The user $fileowner info<br>";
$user_info_array = posix_getpwuid($fileowner);

foreach ($user_info_array as $key => $val) {
   echo "$key => $val<br>";
}

echo "<br>The group $filegroup info<br>";
$group_info_array = posix_getgrgid($filegroup);

foreach ($group_info_array as $key => $val) {
   echo "$key => $val<br>";
}
?>

Notice the error that results from attempting to use on Windows a function that only works on Linux machines. You can either find a Linux machine to run this on, or move on to the next example to get similar information about Windows files.

The is_dir() and is_file() Functions

Often you must know whether a file is a directory (remember, directories and files are all files, but directories are a special kind of file). For example, suppose you want to create a system that travels through the hierarchy of folders, you'd need to detect when a file was actually a folder, so you could attempt to enter the folder and continue traveling the hierarchy. By the same token, if you want to view only the files in a folder, you'd need to detect when a file is a file. PHP has two functions to help you out:
  • is_dir() is designed specifically to work with directories. It returns True if the given filename refers to a directory.
  • is_file() returns True if the given filename refers to a regular file.
It's very simple to rewrite the previous script so that it produces the same results using these functions:


<?php
$filename = "./counter.php";
if(is_dir($filename)) {
 echo "$filename is a directory.";
} else if (is_file($filename)) {
 echo "$filename is a file.";
} else {
 echo "$filename is neither a directory nor a file.";
}
?>

As noted earlier, if you use fileatime() in Windows, it returns the last modified date; and because Windows doesn't support file ownership, filegroup() and fileowner() both return zero.


Try it Out: Get Information on a Windows File
Start example
Here's a sample script that displays some properties on a given file:


<?php
//file_win_info.php
function date_str($timestamp) {
   $date_str = getdate($timestamp);
   $year = $date_str["year"];
   $mon = $date_str["mon"];
   $mday = $date_str["mday"];
   $hours = $date_str["hours"];
   $minutes = $date_str["minutes"];
   $seconds = $date_str["seconds"];
   return "$hours:$minutes:$seconds $mday/$mon/$year";
}
function file_info($file) {

   $file_info_array["filesize"] =
                  number_format(filesize($file)) . " bytes.";
   $file_info_array["filectime"] = date_str(filectime($file));
   $file_info_array["filemtime"] = date_str(filemtime($file));
   if(!isset($_ENV[WINDIR])) {
      $file_info_array["fileatime"] = date_str(fileatime($file));
      $file_info_array["filegroup"] = filegroup($file);
      $file_info_array["fileowner"] = fileowner($file);
}
$file_info_array["filetype"] = filetype($file);

return $file_info_array;
}

$filename = "./count.dat";
$file_info_array = file_info($filename);

echo "<center>Stats for $filename</center>";
foreach($file_info_array as $key=>$val) {
   echo ucfirst($key) . "=>". $val . "<br>";
}
?>


End example

How it Works

Taking some lines of code from the last version of the hit counter, you can put them in a complete function named date_str(), which returns a formatted date string:


function date_str($timestamp) {
   $date_str = getdate($timestamp);
   $year = $date_str["year"];
   $mon = $date_str["mon"];
   $mday = $date_str["mday"];
   $hours = $date_str["hours"];
   $minutes = $date_str["minutes"];
   $seconds = $date_str["seconds"];

   return "$hours:$minutes:$seconds $mday/$mon/$year";
}

The next file_info() function introduces a set of new file-related functions that return useful information on a given file:


function file_info($file) {
   $file_info_array["filesize"] =
                  number_format(filesize($file)) . " bytes.";
   $file_info_array["filectime"] = date_str(filectime($file));
   $file_info_array["filemtime"] = date_str(filemtime($file));

if(!isset($_ENV[WINDIR""])) {
   $file_info_array["fileatime"] = date_str(fileatime($file));
   $file_info_array["filegroup"] = filegroup($file);
   $file_info_array["fileowner"] = fileowner($file);
}

$file_info_array["filetype"] = filetype($file);
return $file_info_array;
}

The environment variable $_ENV[WINDIR] is only set on the Windows platform; you access it via $_ENV and use it as a flag to denote whether the script is being run on a Windows platform. If it is set in the preceding code, you don't read the three fields that Windows doesn't support. Please note that the old $HTTP_ENV_VARS could be used as well, so long as you used the global keyword on it to make it visible inside your function. Although that still works, it's deprecated in favor of the $_ENV superglobal. An advantage of using the superglobal $_ENV is that you don't have to declare it as global to access from inside functions.


Finally, you specify a file, call the file_info() function, and print out the contents of each element in the array it returns:


$filename = "./count.dat";
$file_info_array = file_info($filename);

echo "<center>Stats for $filename</center>";
foreach($file_info_array as $key=>$val) {
   echo ucfirst($key) . "=>". $val . "<br>";
}