davadmin/admin/directories.php

323 lines
9.7 KiB
PHP

<?php
/**
* Directory administration code.
*
* @author Jan Dittberner <jan@dittberner.info>
* @version $Id$
* @license GPL
* @package DAVAdmin
*
* Copyright (c) 2007, 2008 Jan Dittberner
*
* This file is part of DAVAdmin.
*
* DAVAdmin 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; either version 3 of the License, or
* (at your option) any later version.
*
* DAVAdmin 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 DAVAdmin; if not, see <http://www.gnu.org/licenses/>.
*/
/** Include common code. */
include_once('common.inc.php');
/** Format string for group lines in .htaccess files. */
define('GROUPLINEFORMAT', "require group %s\n");
/** Regular expression for finding group lines in .htaccess files. */
define('GROUPLINERE', '/^require\s+group\s+(.*)$/i');
/** Regular expression matching legal directory names. */
define('DIRNAMERE', '/^[a-zA-Z0-9 -_.]+$/');
/**
* List of mandatory groups. These groups are assigned to every new or
* changed directory.
*/
$mandatorygroups = array(ADMIN_GROUP);
/**
* Gets the group names allowed to access the given directory from its
* .htaccess file. Mandatory groups are excluded.
*
* @param string $dirname a fully qualified directory name
* @return array an array of group names
*/
function getDirGroupsFromHtaccess($dirname) {
$htaccessname = getFullPath($dirname) . DIRECTORY_SEPARATOR . ".htaccess";
$groups = array();
if (false !== ($fh = fopen($htaccessname, "r"))) {
while (!feof($fh)) {
$buffer = fgets($fh);
if (preg_match_all(GROUPLINERE, trim($buffer), $matches)) {
$grouparr = explode(" ", $matches[1][0]);
foreach ($grouparr as $group) {
$group = trim($group);
if (!in_array($group, $GLOBALS['mandatorygroups']) &&
!in_array($group, $groups)) {
array_push($groups, $group);
}
}
}
}
}
fclose($fh);
return $groups;
}
/**
* Counts the visible files and their accumulated size in a directory
* tree.
*
* @param string $dirname a fully qualified directory name
* @param array $retval a two component array index 0 is the file
* count, index 1 is the accumulated size of files
* @return array array updated with the data from subdirectories and
* files of $dirname
*/
function countFilesRecursive($dirname, $retval = array(0, 0)) {
$dh = opendir($dirname);
while (false !== ($entry = readdir($dh))) {
$fullname = $dirname . DIRECTORY_SEPARATOR . $entry;
if (strpos($entry, '.') !== 0) {
if (is_dir($fullname)) {
$retval = countFilesRecursive($fullname, $retval);
} else if (is_file($fullname)) {
$retval = array($retval[0] + 1, $retval[1] + filesize($fullname));
}
}
}
closedir($dh);
return $retval;
}
/**
* Gets the data of a directory.
*
* @param string $dirname a fully qualified directory name
* @return array array containing directory data
*/
function getDirectoryData($dirname) {
$dir = array();
$dir['name'] = basename($dirname);
$dir['groups'] = getDirGroupsFromHtaccess($dirname);
list($dir['filecount'], $dir['filesize']) = countFilesRecursive(getFullPath($dirname));
$dir['maydelete'] = ($dir['filecount'] == 0) ? 1 : 0;
$dir['filesize'] = sprintf(_("%d kBytes"), $dir['filesize'] / 1024);
return $dir;
}
/**
* Gets XML encoded data of a directory.
*
* @param string $dirname dirname relative to {@link $davconfig['dav.dir']}
* @return string XML string
*/
function getDirectoryDataAsXml($dirname) {
if (is_dir(getFullPath($dirname))) {
$dirdata = getDirectoryData($dirname);
header("Content-Type: text/xml; charset=UTF-8");
return sprintf('<?xml version="1.0" encoding="utf8"?><directory><dirname>%s</dirname><groups>%s</groups><filecount>%d</filecount><filesize>%s</filesize><maydelete>%d</maydelete></directory>', $dirdata['name'], implode(", ", $dirdata['groups']), $dirdata['filecount'], $dirdata['filesize'], $dirdata['maydelete']);
} else {
errorAsXml(sprintf(_("Invalid directory name %s!"), $dirname));
}
}
/**
* Gets XML encoded data of a deleted directory.
*
* @param string $dirname directory name relative to $davconfig['dav.dir']
* @return string XML string
*/
function getDeletedDirectoryData($dirname) {
header("Content-Type: text/xml; charset=UTF-8");
return sprintf('<?xml version="1.0" encoding="utf8"?><directory><dirname>%s</dirname></directory>', $dirname);
}
/**
* Gets the list of directory data for all valid directories below
* {@link $davconfig['dav.dir']}.
*
* @return array array of directory data arrays
* @see #getDirectoryData(string)
*/
function getDirectories() {
$dirs = array();
if (false !== ($entries = scandir($GLOBALS['davconfig']['dav.dir']))) {
foreach ($entries as $entry) {
if (is_dir(getFullPath($entry))) {
if (strpos($entry, '.') !== 0) {
if ($entry != ADMIN_DIR) {
array_push($dirs, getDirectoryData($entry));
}
}
}
}
}
return $dirs;
}
/**
* Sets the groups of a directory in its .htaccess file. Mandatory
* groups are added automatically.
*
* @param string $dirname directory name relative to {@link $davconfig['dav.dir']}
* @param array &$groups reference to a list of group names
*/
function setGroups($dirname, &$groups) {
$fullname = getFullPath($dirname);
foreach ($groups as $key => $value) {
$groups[$key] = trim($value);
}
foreach ($GLOBALS['mandatorygroups'] as $mgroup) {
if (!in_array($mgroup, $groups)) {
array_push($groups, $mgroup);
}
}
$groups = array_unique($groups);
asort($groups);
$found = false;
$lines = array();
$found = false;
if (is_dir($fullname)) {
$htaccess = $fullname . DIRECTORY_SEPARATOR . ".htaccess";
if (file_exists($htaccess) && (false !== ($fh = fopen($htaccess, "r")))) {
while (!feof($fh)) {
$buffer = fgets($fh);
if (preg_match(GROUPLINERE, $buffer)) {
array_push($lines, sprintf(GROUPLINEFORMAT, join(" ", $groups)));
$found = true;
} else {
array_push($lines, $buffer);
}
}
fclose($fh);
}
if (!$found) {
array_push($lines, sprintf(GROUPLINEFORMAT, join(" ", $groups)));
}
if (false !== ($fh = fopen($htaccess, "w"))) {
foreach ($lines as $line) {
fwrite($fh, $line);
}
fclose($fh);
}
}
}
/**
* Updates a directory to be accessible by the given list of
* groups. The directory is created if it doesn't exist.
*
* @param string $dirname directory name relative to $davconfig['dav.dir']
* @param array $groups a list of group names
*/
function updateDirectory($dirname, $groups) {
if (preg_match(DIRNAMERE, $dirname, $matches)) {
if ($dirname != ADMIN_DIR) {
$fullname = getFullPath($dirname);
if (file_exists($fullname)) {
if (!is_dir($fullname)) {
errorAsXml(sprintf(_("There already is a directory entry named %s, but it's not a directory!"), $dirname));
}
} else {
mkdir($fullname);
}
setGroups($dirname, $groups);
}
return;
}
errorAsXml(sprintf(_("Invalid directory name %s!"), $dirname));
}
/**
* Recursively deletes the given directory.
*
* @param string $fullname fully qualified directory name
*/
function delrecursive($fullname) {
$dh = opendir($fullname);
while (false !== ($entry = readdir($dh))) {
if ($entry != "." && $entry != "..") {
$entryname = $fullname . DIRECTORY_SEPARATOR . $entry;
if (is_dir($entryname)) {
delrecursive($entryname);
} else {
unlink($entryname);
}
}
}
closedir($dh);
rmdir($fullname);
return true;
}
/**
* Deletes the given directory if it has a valid name and is not the
* administration interface directory.
*
* @param string $dirname directory name relative to $davconfig['dav.dir']
*/
function deleteDirectory($dirname) {
global $davconfig;
if (preg_match(DIRNAMERE, $dirname, $matches)) {
$fullname = $davconfig['dav.dir'] . DIRECTORY_SEPARATOR . $dirname;
if (is_dir($fullname)) {
return delrecursive($fullname);
}
}
errorAsXml(sprintf(_("Invalid directory name %s!"), $dirname));
}
if ($_GET) {
// handle get requests with data
if ($_GET['method']) {
switch ($_GET['method']) {
case 'getdirectorydata':
print getDirectoryDataAsXml($_GET['dirname']);
break;
default:
errorAsXml(sprintf(_("Unexpected values %s!"), serialize($_GET)));
}
} else if (isset($_GET["language"])) {
header("Content-Type: text/html; charset=UTF-8");
$smarty->assign("directories", getDirectories());
$smarty->display("directories.html");
} else {
invalidCall();
}
} elseif ($_POST) {
// handle post requests with data
if ($_POST['method']) {
switch ($_POST['method']) {
case 'submitdirectory':
updateDirectory($_POST['dirname'], explode(",", $_POST['groups']));
print getDirectoryDataAsXml($_POST['dirname']);
break;
case 'deletedirectory':
if (deleteDirectory($_POST['dirname'])) {
print getDeletedDirectoryData($_POST['dirname']);
} else {
errorAsXml(_("Delete failed!"));
}
break;
default:
errorAsXml(sprintf(_("Unexpected values %s!"), serialize($_POST)));
}
} else {
invalidCall();
}
} else {
// handle requests without data
header("Content-Type: text/html; charset=UTF-8");
$smarty->assign("directories", getDirectories());
$smarty->display("directories.html");
}
?>