/WebSVN/include/auth.inc
File deleted
/WebSVN/include/command.inc
File deleted
/WebSVN/include/svnlook.inc
File deleted
/WebSVN/include/feedcreator.class.php
File deleted
/WebSVN/include/distconfig.inc
File deleted
/WebSVN/include/configclass.inc
File deleted
/WebSVN/include/PHP/Compat/Function/var_export.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/array_udiff.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/get_include_path.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/ob_get_clean.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/ob_flush.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/restore_include_path.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/array_diff_ukey.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/stripos.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/array_intersect_key.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/array_chunk.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/pg_escape_bytea.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/get_headers.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/set_include_path.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/str_ireplace.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/array_product.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/array_walk_recursive.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/str_split.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/file_put_contents.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/md5_file.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/php_strip_whitespace.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/htmlspecialchars_decode.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/constant.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/fputcsv.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/file_get_contents.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/inet_ntop.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/time_sleep_until.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/debug_print_backtrace.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/ob_clean.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/floatval.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/ibase_timefmt.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/bcpowmod.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/array_uintersect_assoc.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/is_a.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/array_diff_uassoc.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/strripos.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/array_intersect_ukey.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/convert_uudecode.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/image_type_to_mime_type.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/array_diff_assoc.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/str_rot13.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/array_uintersect_uassoc.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/clone.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/pg_affected_rows.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/ini_get_all.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/fprintf.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/str_word_count.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/bcinvert.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/pg_unescape_bytea.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/array_diff_key.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/mime_content_type.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/http_build_query.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/array_udiff_assoc.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/scandir.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/array_uintersect.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/array_key_exists.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/array_change_key_case.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/vprintf.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/substr_compare.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/version_compare.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/inet_pton.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/mhash.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/ob_get_flush.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/array_search.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/html_entity_decode.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/convert_uuencode.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/array_udiff_uassoc.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/array_combine.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/array_intersect_uassoc.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/vsprintf.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/call_user_func_array.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/str_shuffle.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/idate.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/array_intersect_assoc.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Function/strpbrk.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Constant/STD.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Constant/E_STRICT.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Constant/PATH_SEPARATOR.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Constant/UPLOAD_ERR.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Constant/FILE.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Constant/T.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Constant/DIRECTORY_SEPARATOR.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Constant/PHP_EOL.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat/Components.php
File deleted
\ No newline at end of file
/WebSVN/include/PHP/Compat.php
File deleted
\ No newline at end of file
/WebSVN/include/version.inc
File deleted
/WebSVN/include/php5compat.inc
File deleted
/WebSVN/include/config.inc
File deleted
/WebSVN/include/accessfile.inc
File deleted
/WebSVN/include/utils.inc
File deleted
/WebSVN/include/setup.inc
File deleted
/WebSVN/include/template.inc
File deleted
/WebSVN/include/bugtraq.inc
File deleted
/WebSVN/include/.gitignore
0,0 → 1,0
/config.php
/WebSVN/include/authz.php
0,0 → 1,132
<?php
// WebSVN - Subversion repository viewing via the web using PHP
// Copyright (C) 2004-2006 Tim Armes
//
// 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; either version 2 of the License, or
// (at your option) any later version.
//
// 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; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// --
//
// authz.php
//
// Handle SVN access file
 
class Authorization {
var $accessCache = array();
var $accessFile = null;
var $user = null;
 
// {{{ __construct
 
function __construct() {
$this->setUsername();
}
 
// }}}
 
function hasUsername() {
return $this->user !== null;
}
 
function addAccessFile($accessFile) {
$this->accessFile = $accessFile;
}
 
// {{{ setUsername()
//
// Set the username from the current http session
 
function setUsername() {
if (isset($_SERVER['REMOTE_USER'])) {
$this->user = $_SERVER['REMOTE_USER'];
} else if (isset($_SERVER['REDIRECT_REMOTE_USER'])) {
$this->user = $_SERVER['REDIRECT_REMOTE_USER'];
} else if (isset($_SERVER['PHP_AUTH_USER'])) {
$this->user = $_SERVER['PHP_AUTH_USER'];
}
}
 
// }}}
 
// Private function to simplify creation of common SVN authz command string text.
function svnAuthzCommandString($repo, $path, $checkSubDirs = false) {
global $config;
 
$cmd = $config->getSvnAuthzCommand();
$repoAndPath = '--repository ' . quote($repo) . ' --path ' . quote($path);
$username = !$this->hasUsername() ? '' : '--username ' . quote($this->user);
$subDirs = !$checkSubDirs ? '' : '-R';
$authzFile = quote($this->accessFile);
$retVal = "{$cmd} {$repoAndPath} {$username} {$subDirs} {$authzFile}";
 
return $retVal;
}
 
// {{{ hasReadAccess
//
// Returns true if the user has read access to the given path
 
function hasReadAccess($repos, $path, $checkSubDirs = false) {
if ($this->accessFile == null)
return false;
 
if ($path == '' || $path[0] != '/') {
$path = '/'.$path;
}
 
$cmd = $this->svnAuthzCommandString($repos, $path, $checkSubDirs);
$result = 'no';
 
// Access checks might be issued multiple times for the same repos and paths within one and
// the same request, introducing a lot of overhead because of "svnauthz" especially with
// many repos under Windows. The easiest way to somewhat optimize it for different scenarios
// is using a cache.
//
// https://github.com/websvnphp/websvn/issues/78#issuecomment-489306169
$cache =& $this->accessCache;
$cached = isset($cache[$cmd]) ? $cache[$cmd] : null;
$cachedWhen = isset($cached) ? $cached['when'] : 0;
$cachedExpired = (time() - 60) > $cachedWhen;
 
if ($cachedExpired) {
// Sorting by "when" should be established somehow to only remove the oldest element
// instead of an arbitrary first one, which might be the newest added last time.
if (count($cache) >= 1000) {
array_shift($cache);
}
 
$result = runCommand($cmd)[0];
$cache[$cmd] = array('when' => time(),
'result' => $result);
} else {
$result = $cached['result'];
}
 
return $result != 'no';
}
 
// }}}
 
// {{{ hasUnrestrictedReadAccess
//
// Returns true if the user has read access to the given path and too
// all subdirectories
 
function hasUnrestrictedReadAccess($repos, $path) {
return $this->hasReadAccess($repos, $path, true);
}
 
// }}}
 
}
/WebSVN/include/bugtraq.php
0,0 → 1,371
<?php
// WebSVN - Subversion repository viewing via the web using PHP
// Copyright (C) 2004-2006 Tim Armes
//
// 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; either version 2 of the License, or
// (at your option) any later version.
//
// 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; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// --
//
// bugtraq.php
//
// Functions for accessing the bugtraq properties and replacing issue IDs
// with URLs.
//
// For more information about bugtraq, see
// http://svn.collab.net/repos/tortoisesvn/trunk/doc/issuetrackers.txt
 
class Bugtraq {
// {{{ Properties
 
var $msgstring;
var $urlstring;
var $logregex;
var $append;
 
var $firstPart;
var $firstPartLen;
var $lastPart;
var $lastPartLen;
 
var $propsfound = false;
 
// }}}
 
// {{{ __construct($rep, $svnrep, $path)
 
function __construct($rep, $svnrep, $path) {
global $config;
 
if ($rep->isBugtraqEnabled()) {
$enoughdata = false;
if (($properties = $rep->getBugtraqProperties()) !== null) {
$this->msgstring = $properties['bugtraq:message'];
$this->logregex = $properties['bugtraq:logregex'];
$this->urlstring = $properties['bugtraq:url'];
$this->append = $properties['bugtraq:append'];
$enoughdata = true;
} else {
$pos = strrpos($path, '/');
$parent = substr($path, 0, $pos + 1);
$this->append = true;
 
while (!$enoughdata && (strpos($parent, '/') !== false)) {
$properties = $svnrep->getProperties($parent);
if (empty($this->msgstring) && in_array('bugtraq:message', $properties)) $this->msgstring = $svnrep->getProperty($parent, 'bugtraq:message');
if (empty($this->logregex) && in_array('bugtraq:logregex', $properties)) $this->logregex = $svnrep->getProperty($parent, 'bugtraq:logregex');
if (empty($this->urlstring) && in_array('bugtraq:url', $properties)) $this->urlstring = $svnrep->getProperty($parent, 'bugtraq:url');
if (in_array('bugtraq:append', $properties) && $svnrep->getProperty($parent, 'bugtraq:append') == 'false') $this->append = false;
 
$parent = substr($parent, 0, -1); // Remove the trailing slash
$pos = strrpos($parent, '/'); // Find the last trailing slash
$parent = substr($parent, 0, $pos + 1); // Find the previous parent directory
$enoughdata = ((!empty($this->msgstring) || !empty($this->logregex)) && !empty($this->urlstring));
}
}
 
$this->msgstring = trim(@$this->msgstring);
$this->urlstring = trim(@$this->urlstring);
 
if ($enoughdata && !empty($this->msgstring)) {
$this->initPartInfo();
}
 
if ($enoughdata) {
$this->propsfound = true;
}
}
}
 
// }}}
 
// {{{ initPartInfo()
 
function initPartInfo() {
if (($bugidpos = strpos($this->msgstring, '%BUGID%')) !== false && strpos($this->urlstring, '%BUGID%') !== false) {
// Get the textual parts of the message string for comparison purposes
$this->firstPart = substr($this->msgstring, 0, $bugidpos);
$this->firstPartLen = strlen($this->firstPart);
$this->lastPart = substr($this->msgstring, $bugidpos + 7);
$this->lastPartLen = strlen($this->lastPart);
}
}
 
// }}}
 
// {{{ replaceIDs($message)
 
function replaceIDs($message) {
if (!$this->propsfound) return $message;
 
// First we search for the message string
$logmsg = '';
$message = rtrim($message);
 
if ($this->append) {
// Just compare the last line
if (($offset = strrpos($message, "\n")) !== false) {
$logmsg = substr($message, 0, $offset + 1);
$bugLine = substr($message, $offset + 1);
} else {
$bugLine = $message;
}
} else {
if (($offset = strpos($message, "\n")) !== false) {
$bugLine = substr($message, 0, $offset);
$logmsg = substr($message, $offset);
} else {
$bugLine = $message;
}
}
 
// Make sure that our line really is an issue tracker message
if (isset($this->firstPart) && isset($this->lastPart) && ((strncmp($bugLine, $this->firstPart, $this->firstPartLen) == 0)) && strcmp(substr($bugLine, -$this->lastPartLen, $this->lastPartLen), $this->lastPart) == 0) {
// Get the issues list
if ($this->lastPartLen > 0) {
$issues = substr($bugLine, $this->firstPartLen, -$this->lastPartLen);
} else {
$issues = substr($bugLine, $this->firstPartLen);
}
 
// Add each reference to the first part of the line
$line = $this->firstPart;
while ($pos = strpos($issues, ',')) {
$issue = trim(substr($issues, 0, $pos));
$issues = substr($issues, $pos + 1);
 
$line .= '<a href="'.str_replace('%BUGID%', $issue, $this->urlstring).'">'.$issue.'</a>, ';
}
$line .= '<a href="'.str_replace('%BUGID%', trim($issues), $this->urlstring).'">'.trim($issues).'</a>'.$this->lastPart;
 
if ($this->append) {
$message = $logmsg.$line;
} else {
$message = $line.$logmsg;
}
}
 
// Now replace all other instances of bug IDs that match the regex
if ($this->logregex) {
$message = rtrim($message);
$line = '';
$allissues = '';
 
$lines = explode("\n", $this->logregex);
$regex_all = '~'.$lines[0].'~';
$regex_single = @$lines[1];
 
if (empty($regex_single)) {
// If the property only contains one line, then the pattern is only designed
// to find one issue number at a time. e.g. [Ii]ssue #?(\d+). In this case
// we need to replace the matched issue ID with the link.
 
if ($numMatches = preg_match_all($regex_all, $message, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) {
$addedOffset = 0;
for ($match = 0; $match < $numMatches; $match++) {
$issue = $matches[$match][1][0];
$issueOffset = $matches[$match][1][1];
 
$issueLink = '<a href="'.str_replace('%BUGID%', $issue, $this->urlstring).'">'.$issue.'</a>';
$message = substr_replace($message, $issueLink, $issueOffset + $addedOffset, strlen($issue));
$addedOffset += strlen($issueLink) - strlen($issue);
}
}
} else {
// It the property contains two lines, then the first is a pattern for extracting
// multiple issue numbers, and the second is a pattern extracting each issue
// number from the multiple match. e.g. [Ii]ssue #?(\d+)(,? ?#?(\d+))+ and (\d+)
 
while (preg_match($regex_all, $message, $matches, PREG_OFFSET_CAPTURE)) {
$completeMatch = $matches[0][0];
$completeMatchOffset = $matches[0][1];
 
$replacement = $completeMatch;
 
if ($numMatches = preg_match_all('~'.$regex_single.'~', $replacement, $matches, PREG_SET_ORDER | PREG_OFFSET_CAPTURE)) {
$addedOffset = 0;
for ($match = 0; $match < $numMatches; $match++) {
$issue = $matches[$match][1][0];
$issueOffset = $matches[$match][1][1];
 
$issueLink = '<a href="'.str_replace('%BUGID%', $issue, $this->urlstring).'">'.$issue.'</a>';
$replacement = substr_replace($replacement, $issueLink, $issueOffset + $addedOffset, strlen($issue));
$addedOffset += strlen($issueLink) - strlen($issue);
}
}
 
$message = substr_replace($message, $replacement, $completeMatchOffset, strlen($completeMatch));
}
}
}
 
return $message;
}
 
// }}}
 
}
 
// The BugtraqTestable class is a derived class that is used to test the matching
// abilities of the Bugtraq class. In particular, it allows for the initialisation of the
// class without the need for a repository.
 
class BugtraqTestable extends Bugtraq {
// {{{ __construct()
 
function __construct() {
// This constructor serves to assure that the parent constructor is not
// called.
}
 
// }}}
 
// {{{ setUpVars($message, $url, $regex, $append)
 
function setUpVars($message, $url, $regex, $append) {
$this->msgstring = $message;
$this->urlstring = $url;
$this->logregex = $regex;
$this->append = $append;
$this->propsfound = true;
 
$this->initPartInfo();
}
 
// }}}
 
// {{{ setMessage($message)
 
function setMessage($message) {
$this->msgstring = $message;
}
 
// }}}
 
// {{{ setUrl($url)
 
function setUrl($url) {
$this->urlstring = $url;
}
 
// }}}
 
// {{{ setRegex($regex)
 
function setRegEx($regex) {
$this->logregex = $regex;
}
 
// }}}
 
// {{{ setAppend($append)
 
function setAppend($append) {
$this->append = $append;
}
 
// }}}
 
// {{{ printVars()
 
function printVars() {
echo 'msgstring = '.$this->msgstring."\n";
echo 'urlstring = '.$this->urlstring."\n";
echo 'logregex = '.$this->logregex."\n";
echo 'append = '.$this->append."\n";
 
echo 'firstPart = '.$this->firstPart."\n";
echo 'firstPartLen = '.$this->firstPartLen."\n";
echo 'lastPart = '.$this->lastPart."\n";
echo 'lastPartLen = '.$this->lastPartLen."\n";
}
 
// }}}
}
 
// {{{ test_bugtraq()
 
function test_bugtraq() {
$tester = new BugtraqTestable;
 
$tester->setUpVars('BugID: %BUGID%',
'http://bugtracker/?id=%BUGID%',
'[Ii]ssue #?(\d+)',
true
);
 
//$tester->printVars();
 
$res = $tester->replaceIDs('BugID: 789'."\n".
'This is a test message that refers to issue #123 and'."\n".
'issue #456.'."\n".
'BugID: 789'
);
 
echo nl2br($res).'<p>';
 
$res = $tester->replaceIDs('BugID: 789, 101112'."\n".
'This is a test message that refers to issue #123 and'."\n".
'issue #456.'."\n".
'BugID: 789, 101112'
);
 
echo nl2br($res).'<p>';
 
$tester->setAppend(false);
 
$res = $tester->replaceIDs('BugID: 789'."\n".
'This is a test message that refers to issue #123 and'."\n".
'issue #456.'."\n".
'BugID: 789'
);
 
echo nl2br($res).'<p>';
 
$res = $tester->replaceIDs('BugID: 789, 101112'."\n".
'This is a test message that refers to issue #123 and'."\n".
'issue #456.'."\n".
'BugID: 789, 101112'
);
 
echo nl2br($res).'<p>';
 
$tester->setUpVars('BugID: %BUGID%',
'http://bugtracker/?id=%BUGID%',
'[Ii]ssues?:?(\s*(,|and)?\s*#\d+)+\n(\d+)',
true
);
 
$res = $tester->replaceIDs('BugID: 789, 101112'."\n".
'This is a test message that refers to issue #123 and'."\n".
'issues #456, #654 and #321.'."\n".
'BugID: 789, 101112'
);
 
echo nl2br($res).'<p>';
 
$tester->setUpVars('Test: %BUGID%',
'http://bugtracker/?id=%BUGID%',
'\s*[Cc]ases*\s*[IDs]*\s*[#: ]+((\d+[ ,:;#]*)+)\n(\d+)',
true
);
 
$res = $tester->replaceIDs('Cosmetic change'."\n".
'CaseIDs: 48'
);
 
echo nl2br($res).'<p>';
}
 
// }}}
/WebSVN/include/command.php
0,0 → 1,209
<?php
// WebSVN - Subversion repository viewing via the web using PHP
// Copyright (C) 2004-2006 Tim Armes
//
// 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; either version 2 of the License, or
// (at your option) any later version.
//
// 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; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// --
//
// command.php
//
// External command handling
 
function detectCharacterEncoding($str) {
$list = array('UTF-8', 'ISO-8859-1', 'windows-1252');
if (function_exists('mb_detect_encoding')) {
foreach ($list as $item) {
if (mb_check_encoding($str, $item)) return $item;
}
 
} else if (function_exists('iconv')) {
foreach ($list as $item) {
$encstr = iconv($item, $item.'//TRANSLIT//IGNORE', $str);
if (md5($encstr) == md5($str)) return $item;
}
}
 
return null;
}
 
// {{{ toOutputEncoding
 
function toOutputEncoding($str) {
$enc = detectCharacterEncoding($str);
 
if ($enc !== null && function_exists('mb_convert_encoding')) {
$str = mb_convert_encoding($str, 'UTF-8', $enc);
 
} else if ($enc !== null && function_exists('iconv')) {
$str = iconv($enc, 'UTF-8//TRANSLIT//IGNORE', $str);
 
} else {
// @see http://w3.org/International/questions/qa-forms-utf-8.html
$isUtf8 = preg_match('%^(?:
[\x09\x0A\x0D\x20-\x7E] # ASCII
| [\xC2-\xDF][\x80-\xBF] # non-overlong 2-byte
| \xE0[\xA0-\xBF][\x80-\xBF] # excluding overlongs
| [\xE1-\xEC\xEE\xEF][\x80-\xBF]{2} # straight 3-byte
| \xED[\x80-\x9F][\x80-\xBF] # excluding surrogates
| \xF0[\x90-\xBF][\x80-\xBF]{2} # planes 1-3
| [\xF1-\xF3][\x80-\xBF]{3} # planes 4-15
| \xF4[\x80-\x8F][\x80-\xBF]{2} # plane 16
)*$%xs', $str
);
if (!$isUtf8) $str = utf8_encode($str);
}
 
return $str;
}
 
// }}}
 
// {{{ escape
//
// Escape a string to output
 
function escape($str) {
$entities = array();
$entities['&'] = '&amp;';
$entities['<'] = '&lt;';
$entities['>'] = '&gt;';
$entities['"'] = '&quot;';
$entities['\''] = '&apos;';
return str_replace(array_keys($entities), array_values($entities), $str ?? '');
}
 
// }}}
 
// {{{ execCommand
 
function execCommand($cmd, &$retcode) {
return @exec($cmd, $tmp, $retcode);
}
 
// }}}
 
// {{{ popenCommand
 
function popenCommand($cmd, $mode) {
return popen($cmd, $mode);
}
 
// }}}
 
// {{{ passthruCommand
 
function passthruCommand($cmd) {
return passthru($cmd);
}
 
// }}}
 
// {{{ runCommand
 
function runCommand($cmd, $mayReturnNothing = false, &$errorIf = 'NOT_USED') {
global $config, $lang;
 
$output = array();
$error = '';
$opts = null;
 
// https://github.com/websvnphp/websvn/issues/75
// https://github.com/websvnphp/websvn/issues/78
if ($config->serverIsWindows) {
if (!strpos($cmd, '>') && !strpos($cmd, '|')) {
$opts = array('bypass_shell' => true);
} else {
$cmd = '"'.$cmd.'"';
}
}
 
$descriptorspec = array(0 => array('pipe', 'r'), 1 => array('pipe', 'w'), 2 => array('pipe', 'w'));
$resource = proc_open($cmd, $descriptorspec, $pipes, null, null, $opts);
 
if (!is_resource($resource)) {
echo '<p>'.$lang['BADCMD'].': <code>'.stripCredentialsFromCommand($cmd).'</code></p>';
exit;
}
 
$handle = $pipes[1];
$firstline = true;
 
while (!feof($handle)) {
$line = rtrim(fgets($handle), "\n\r");
if ($firstline && empty($line) && !$mayReturnNothing) {
$error = 'No output on STDOUT.';
break;
}
 
$firstline = false;
$output[] = toOutputEncoding($line);
}
 
while (!feof($pipes[2])) {
$error .= fgets($pipes[2]);
}
$error = toOutputEncoding(trim($error));
 
fclose($pipes[0]);
fclose($pipes[1]);
fclose($pipes[2]);
 
proc_close($resource);
 
# Some commands are expected to return no output, but warnings on STDERR.
if ((count($output) > 0) || $mayReturnNothing) {
return $output;
}
 
if ($errorIf != 'NOT_USED') {
$errorIf = $error;
return $output;
}
 
echo '<p>'.$lang['BADCMD'].': <code>'.stripCredentialsFromCommand($cmd).'</code></p>';
echo '<p>'.nl2br($error).'</p>';
exit;
}
 
// }}}
 
function stripCredentialsFromCommand($cmd) {
global $config;
 
$quotingChar = ($config->serverIsWindows ? '"' : "'");
$quotedString = $quotingChar.'([^'.$quotingChar.'\\\\]*(\\\\.[^'.$quotingChar.'\\\\]*)*)'.$quotingChar;
$patterns = array('|--username '.$quotedString.' |U', '|--password '.$quotedString.' |U');
$replacements = array('--username '.quote('***').' ', '--password '.quote('***').' ');
$cmd = preg_replace($patterns, $replacements, $cmd, 1);
 
return $cmd;
}
 
// {{{ quote
//
// Quote a string to send to the command line
 
function quote($str) {
global $config;
 
if ($config->serverIsWindows) {
return '"'.$str.'"';
} else {
return escapeshellarg($str);
}
}
 
// }}}
/WebSVN/include/configclass.php
0,0 → 1,1702
<?php
// WebSVN - Subversion repository viewing via the web using PHP
// Copyright (C) 2004-2006 Tim Armes
//
// 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; either version 2 of the License, or
// (at your option) any later version.
//
// 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; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// --
//
// configclass.php
//
// General class for handling configuration options
 
require_once 'include/command.php';
require_once 'include/authz.php';
require_once 'include/version.php';
 
// Auxillary functions used to sort repositories by name/group
 
// {{{ cmpReps($a, $b)
 
function cmpReps($a, $b) {
// First, sort by group
$g = strcasecmp((string) $a->group, (string) $b->group);
if ($g) return $g;
 
// Same group? Sort by name
return strcasecmp($a->name, $b->name);
}
 
// }}}
 
// {{{ cmpGroups($a, $b)
 
function cmpGroups($a, $b) {
$g = strcasecmp((string) $a->group, (string) $b->group);
if ($g) return $g;
 
return 0;
}
 
// }}}
 
// {{{ mergesort(&$array, [$cmp_function])
 
function mergesort(&$array, $cmp_function = 'strcmp') {
// Arrays of size < 2 require no action
 
if (count($array) < 2) return;
 
// Split the array in half
$halfway = count($array) / 2;
$array1 = array_slice($array, 0, $halfway);
$array2 = array_slice($array, $halfway);
 
// Recurse to sort the two halves
mergesort($array1, $cmp_function);
mergesort($array2, $cmp_function);
 
// If all of $array1 is <= all of $array2, just append them.
if (call_user_func($cmp_function, end($array1), $array2[0]) < 1) {
$array = array_merge($array1, $array2);
return;
}
 
// Merge the two sorted arrays into a single sorted array
$array = array();
$array1count = count($array1);
$array2count = count($array2);
$ptr1 = 0;
$ptr2 = 0;
while ($ptr1 < $array1count && $ptr2 < $array2count) {
if (call_user_func($cmp_function, $array1[$ptr1], $array2[$ptr2]) < 1) {
$array[] = $array1[$ptr1++];
} else {
$array[] = $array2[$ptr2++];
}
}
 
// Merge the remainder
while ($ptr1 < $array1count) $array[] = $array1[$ptr1++];
while ($ptr2 < $array2count) $array[] = $array2[$ptr2++];
 
return;
}
 
// }}}
 
// A Repository parent path configuration class
 
class ParentPath {
// {{{ Properties
 
var $path;
var $group;
var $pattern;
var $skipAlreadyAdded;
var $clientRootURL;
 
// }}}
 
// {{{ __construct($path [, $group [, $pattern [, $skipAlreadyAdded [, $clientRootURL]]]])
function __construct($path, $group = null, $pattern = false, $skipAlreadyAdded = true, $clientRootURL = '') {
$this->path = $path;
$this->group = $group;
$this->pattern = $pattern;
$this->skipAlreadyAdded = $skipAlreadyAdded;
$this->clientRootURL = rtrim($clientRootURL, '/');
}
// }}}
 
// {{{ findRepository($name)
// look for a repository with $name
function &findRepository($name) {
global $config;
if ($this->group != null) {
$prefix = $this->group.'.';
if (substr($name, 0, strlen($prefix)) == $prefix) {
$name = substr($name, strlen($prefix));
} else {
$null = null;
return $null;
}
}
// is there a directory named $name?
$fullpath = $this->path.DIRECTORY_SEPARATOR.$name;
if (is_dir($fullpath) && is_readable($fullpath)) {
// And that contains a db directory (in an attempt to not include non svn repositories.
$dbfullpath = $fullpath.DIRECTORY_SEPARATOR.'db';
if (is_dir($dbfullpath) && is_readable($dbfullpath)) {
// And matches the pattern if specified
if ($this->pattern === false || preg_match($this->pattern, $name)) {
$url = $config->fileUrlPrefix.$fullpath;
$url = str_replace(DIRECTORY_SEPARATOR, '/', $url);
if ($url[ strlen($url) - 1 ] == '/') {
$url = substr($url, 0, -1);
}
 
if (!in_array($url, $config->_excluded, true)) {
$clientRootURL = ($this->clientRootURL) ? $this->clientRootURL.'/'.$name : '';
$rep = new Repository($name, $name, $url, $this->group, null, null, null, $clientRootURL);
return $rep;
}
}
}
}
$null = null;
return $null;
}
// }}}
 
// {{{ getRepositories()
// return all repositories in the parent path matching pattern
function &getRepositories() {
global $config;
$repos = array();
$handle = @opendir($this->path);
 
if (!$handle) return $repos;
 
// For each file...
while (false !== ($name = readdir($handle))) {
$fullpath = $this->path.DIRECTORY_SEPARATOR.$name;
if ($name[0] != '.' && is_dir($fullpath) && is_readable($fullpath)) {
// And that contains a db directory (in an attempt to not include non svn repositories.
$dbfullpath = $fullpath.DIRECTORY_SEPARATOR.'db';
if (is_dir($dbfullpath) && is_readable($dbfullpath)) {
// And matches the pattern if specified
if ($this->pattern === false || preg_match($this->pattern, $name)) {
$url = $config->fileUrlPrefix.$fullpath;
$url = str_replace(DIRECTORY_SEPARATOR, '/', $url);
if ($url[strlen($url) - 1] == '/') {
$url = substr($url, 0, -1);
}
$clientRootURL = ($this->clientRootURL) ? $this->clientRootURL.'/'.$name : '';
$repos[] = new Repository($name, $name, $url, $this->group, null, null, null, $clientRootURL);
}
}
}
}
closedir($handle);
 
// Sort the repositories into alphabetical order
if (!empty($repos)) {
usort($repos, 'cmpReps');
}
 
return $repos;
}
// }}}
 
// {{{ getSkipAlreadyAdded()
// Return if we should skip already added repos for this parent path.
function getSkipAlreadyAdded() {
return $this->skipAlreadyAdded;
}
// }}}
}
 
// A Repository configuration class
 
class Repository {
// {{{ Properties
 
var $name;
var $svnName;
var $path;
var $subpath;
var $group;
var $username = null;
var $password = null;
var $clientRootURL;
 
// Local configuration options must start off unset
 
var $allowDownload;
var $minDownloadLevel;
var $allowedExceptions = array();
var $disallowedExceptions = array();
var $logsShowChanges;
var $rss;
var $rssCaching;
var $rssMaxEntries;
var $spaces;
var $ignoreSvnMimeTypes;
var $ignoreWebSVNContentTypes;
var $bugtraq;
var $bugtraqProperties;
var $authz = null;
var $templatePath = false;
 
// }}}
 
// {{{ __construct($name, $svnName, $serverRootURL [, $group [, $username [, $password [, $clientRootURL]]]])
 
function __construct($name, $svnName, $serverRootURL, $group = null, $username = null, $password = null, $subpath = null, $clientRootURL = null) {
$this->name = $name;
$this->svnName = $svnName;
$this->path = $serverRootURL;
$this->subpath = $subpath;
$this->group = $group;
$this->username = $username;
$this->password = $password;
$this->clientRootURL = rtrim($clientRootURL, '/');
}
 
// }}}
 
// {{{ getDisplayName()
 
function getDisplayName() {
if (!empty($this->group)) {
return $this->group.'.'.$this->name;
}
 
return $this->name;
}
 
// }}}
 
// {{{ svnCredentials
 
function svnCredentials() {
$params = '';
if ($this->username !== null && $this->username !== '') {
$params .= ' --username '.quote($this->username);
}
if ($this->password !== null) {
$params .= ' --password '.quote($this->password);
}
return $params;
}
 
// }}}
 
// Local configuration accessors
 
function setLogsShowChanges($enabled = true) {
$this->logsShowChanges = $enabled;
}
 
function logsShowChanges() {
global $config;
 
if (isset($this->logsShowChanges))
return $this->logsShowChanges;
else
return $config->logsShowChanges();
}
 
// {{{ RSS Feed
 
function setRssEnabled($enabled) {
$this->rss = $enabled;
}
 
function isRssEnabled() {
global $config;
 
if (isset($this->rss))
return $this->rss;
else
return $config->isRssEnabled();
}
 
function setRssCachingEnabled($enabled = true) {
$this->rssCaching = $enabled;
}
 
function isRssCachingEnabled() {
global $config;
 
if (isset($this->rssCaching))
return $this->rssCaching;
else
return $config->isRssCachingEnabled();
}
 
function setRssMaxEntries($max) {
$this->rssMaxEntries = $max;
}
 
function getRssMaxEntries() {
global $config;
 
if (isset($this->rssMaxEntries))
return $this->rssMaxEntries;
else
return $config->getRssMaxEntries();
}
 
// }}}
 
// {{{ Download
 
function allowDownload() {
$this->allowDownload = true;
}
 
function disallowDownload() {
$this->allowDownload = false;
}
 
function getAllowDownload() {
global $config;
 
if (isset($this->allowDownload)) {
return $this->allowDownload;
}
 
return $config->getAllowDownload();
}
 
function setMinDownloadLevel($level) {
$this->minDownloadLevel = $level;
}
 
function getMinDownloadLevel() {
global $config;
 
if (isset($this->minDownloadLevel)) {
return $this->minDownloadLevel;
}
 
return $config->getMinDownloadLevel();
}
 
function addAllowedDownloadException($path) {
if ($path[strlen($path) - 1] != '/') $path .= '/';
 
$this->allowedExceptions[] = $path;
}
 
function addDisallowedDownloadException($path) {
if ($path[strlen($path) - 1] != '/') $path .= '/';
 
$this->disallowedExceptions[] = $path;
}
 
function isDownloadAllowed($path) {
global $config;
 
// Check global download option
if (!$this->getAllowDownload()) {
return false;
}
 
// Check with access module
if (!$this->hasUnrestrictedReadAccess($path)) {
return false;
}
 
$subs = explode('/', $path);
$level = count($subs) - 2;
if ($level >= $this->getMinDownloadLevel()) {
// Level OK, search for disallowed exceptions
 
if ($config->findException($path, $this->disallowedExceptions)) {
return false;
}
 
if ($config->findException($path, $config->disallowedExceptions)) {
return false;
}
 
return true;
 
} else {
// Level not OK, search for disallowed exceptions
 
if ($config->findException($path, $this->allowedExceptions)) {
return true;
}
 
if ($config->findException($path, $config->allowedExceptions)) {
return true;
}
 
return false;
}
}
 
// }}}
 
// {{{ Templates
 
function setTemplatePath($path) {
$this->templatePath = $path;
}
 
function getTemplatePath() {
global $config;
if (!empty($this->templatePath)) {
return $this->templatePath;
}
 
return $config->getTemplatePath();
}
 
// }}}
 
// {{{ Tab expansion
 
function expandTabsBy($sp) {
$this->spaces = $sp;
}
 
function getExpandTabsBy() {
global $config;
 
if (isset($this->spaces)) {
return $this->spaces;
}
 
return $config->getExpandTabsBy();
}
 
// }}}
 
// {{{ MIME-Type Handing
 
function ignoreSvnMimeTypes() {
$this->ignoreSvnMimeTypes = true;
}
 
function useSvnMimeTypes() {
$this->ignoreSvnMimeTypes = false;
}
 
function getIgnoreSvnMimeTypes() {
global $config;
 
if (isset($this->ignoreSvnMimeTypes)) {
return $this->ignoreSvnMimeTypes;
}
 
return $config->getIgnoreSvnMimeTypes();
}
 
function ignoreWebSVNContentTypes() {
$this->ignoreWebSVNContentTypes = true;
}
 
function useWebSVNContentTypes() {
$this->ignoreWebSVNContentTypes = false;
}
 
function getIgnoreWebSVNContentTypes() {
global $config;
 
if (isset($this->ignoreWebSVNContentTypes)) {
return $this->ignoreWebSVNContentTypes;
}
 
return $config->getIgnoreWebSVNContentTypes();
}
 
// }}}
 
// {{{ Bugtraq issue tracking
 
function setBugtraqEnabled($enabled) {
$this->bugtraq = $enabled;
}
 
function isBugtraqEnabled() {
global $config;
 
if (isset($this->bugtraq))
return $this->bugtraq;
else
return $config->isBugtraqEnabled();
}
 
function setBugtraqProperties($properties) {
$this->bugtraqProperties = $properties;
}
 
function getBugtraqProperties() {
global $config;
 
if (isset($this->bugtraqProperties))
return $this->bugtraqProperties;
else
return $config->getBugtraqProperties();
}
 
// }}}
 
// {{{ Authorization
 
function useAccessFile($file) {
if (is_readable($file)) {
if ($this->authz === null) {
$this->authz = new Authorization();
}
$this->authz->addAccessFile($file);
} else {
die('Unable to read access file "'.$file.'"');
}
}
 
function &getAuthz() {
global $config;
 
$a = null;
if ($this->authz !== null) {
$a =& $this->authz;
} else {
$a =& $config->getAuthz();
}
return $a;
}
 
function _getPathWithSubIf($pathWoSub) {
if (!$this->subpath) {
return $pathWoSub;
}
 
return '/' . $this->subpath . $pathWoSub;
}
 
function hasReadAccess($pathWoSub, $checkSubDirs = false) {
$path = $this->_getPathWithSubIf($pathWoSub);
$a =& $this->getAuthz();
 
if (!empty($a)) {
return $a->hasReadAccess($this->svnName, $path, $checkSubDirs);
}
 
// No access file - free access...
return true;
}
 
function hasLogReadAccess($pathWithSub) {
$path = $pathWithSub;
$a =& $this->getAuthz();
 
if (!empty($a)) {
return $a->hasReadAccess($this->svnName, $path, false);
}
 
// No access file - free access...
return true;
}
 
function hasUnrestrictedReadAccess($pathWoSub) {
$path = $this->_getPathWithSubIf($pathWoSub);
$a =& $this->getAuthz();
 
if (!empty($a)) {
return $a->hasUnrestrictedReadAccess($this->svnName, $path);
}
 
// No access file - free access...
return true;
}
 
// }}}
 
}
 
// The general configuration class
 
class WebSvnConfig {
// {{{ Properties
 
// Tool path locations
 
var $_svnCommandPath = '';
var $_svnConfigDir = '/tmp/websvn';
var $_svnTrustServerCert = false;
var $svn = 'svn --non-interactive --config-dir /tmp/websvn';
var $svnAuthz = 'svnauthz accessof';
var $diff = 'diff';
var $enscript = 'enscript -q';
var $sed = 'sed';
var $gzip = 'gzip';
var $tar = 'tar';
var $zip = 'zip';
var $locale = '';
 
// different modes for file and directory download
 
var $defaultFileDlMode = 'plain';
var $defaultDirectoryDlMode = 'gzip';
 
var $validFileDlModes = array( 'gzip', 'zip', 'plain' );
var $validDirectoryDlModes = array( 'gzip', 'zip' );
 
// Other configuration items
 
var $treeView = true;
var $flatIndex = true;
var $openTree = false;
var $alphabetic = false;
var $showLastModInIndex = true;
var $showLastModInListing = true;
var $showAgeInsteadOfDate = true;
var $_showRepositorySelectionForm = true;
var $_ignoreWhitespacesInDiff = false;
var $serverIsWindows = false;
var $multiViews = false;
var $multiViewsIndex = 'browse';
var $useEnscript = false;
var $useEnscriptBefore_1_6_3 = false;
var $useGeshi = false;
var $geshiScript = 'geshi.php';
var $useParsedown = false;
var $parsedownScript = 'Parsedown.php';
var $inlineMimeTypes = array();
var $allowDownload = false;
var $tempDir = '';
var $minDownloadLevel = 0;
var $allowedExceptions = array();
var $disallowedExceptions = array();
var $logsShowChanges = false;
var $rss = true;
var $rssCaching = false;
var $rssMaxEntries = 40;
var $spaces = 8;
var $bugtraq = false;
var $bugtraqProperties = null;
var $authz = null;
var $blockRobots = false;
 
var $loadAllRepos = false;
 
var $templatePaths = array();
var $userTemplate = false;
 
var $ignoreSvnMimeTypes = false;
var $ignoreWebSVNContentTypes = false;
 
var $subversionVersion = '';
var $subversionMajorVersion = '';
var $subversionMinorVersion = '';
 
var $defaultLanguage = 'en';
var $ignoreAcceptedLanguages = false;
 
var $quote = "'";
var $pathSeparator = ':';
var $fileUrlPrefix = 'file://';
var $breadcrumbRepoRootAsRepo = false;
 
var $_repositories = array();
 
var $_parentPaths = array(); // parent paths to load
 
var $_parentPathsLoaded = false;
 
var $_excluded = array();
 
// }}}
 
// {{{ __construct()
 
function __construct() {
}
 
// }}}
 
// {{{ Repository configuration
 
function addRepository($name, $serverRootURL, $group = null, $username = null, $password = null, $clientRootURL = null) {
$this->addRepositorySubpath($name, $serverRootURL, null, $group, $username, $password, $clientRootURL);
}
 
function addRepositorySubpath($name, $serverRootURL, $subpath, $group = null, $username = null, $password = null, $clientRootURL = null) {
if (DIRECTORY_SEPARATOR != '/') {
$serverRootURL = str_replace(DIRECTORY_SEPARATOR, '/', $serverRootURL);
if ($subpath !== null) {
$subpath = str_replace(DIRECTORY_SEPARATOR, '/', $subpath);
}
}
$serverRootURL = trim($serverRootURL, '/');
$svnName = substr($serverRootURL, strrpos($serverRootURL, '/') + 1);
$this->_repositories[] = new Repository($name, $svnName, $serverRootURL, $group, $username, $password, $subpath, $clientRootURL);
}
 
// Automatically set up the repositories based on a parent path
 
function parentPath($path, $group = null, $pattern = false, $skipAlreadyAdded = true, $clientRootURL = '') {
$this->_parentPaths[] = new ParentPath($path, $group, $pattern, $skipAlreadyAdded, $clientRootURL);
}
 
function addExcludedPath($path) {
$url = $this->fileUrlPrefix.$path;
$url = str_replace(DIRECTORY_SEPARATOR, '/', $url);
if ($url[strlen($url) - 1] == '/') {
$url = substr($url, 0, -1);
}
$this->_excluded[] = $url;
}
 
function getRepositories() {
// lazily load parent paths
if ($this->_parentPathsLoaded) return $this->_repositories;
 
$this->_parentPathsLoaded = true;
 
foreach ($this->_parentPaths as $parentPath) {
$parentRepos = $parentPath->getRepositories();
foreach ($parentRepos as $repo) {
if (!$parentPath->getSkipAlreadyAdded()) {
$this->_repositories[] = $repo;
} else {
// we have to check if we already have a repo with the same svn name
$duplicate = false;
foreach ($this->_repositories as $knownRepos) {
if ($knownRepos->path == $repo->path && $knownRepos->subpath == $repo->subpath) {
$duplicate = true;
break;
}
}
 
if (!$duplicate && !in_array($repo->path, $this->_excluded, true)) {
$this->_repositories[] = $repo;
}
}
}
}
 
return $this->_repositories;
}
 
function &findRepository($name) {
// first look in the "normal repositories"
foreach ($this->_repositories as $index => $rep) {
if (strcmp($rep->getDisplayName(), $name) == 0) {
$repref =& $this->_repositories[$index];
return $repref;
}
}
 
// now if the parent repos have not already been loaded
// check them
if (!$this->_parentPathsLoaded) {
foreach ($this->_parentPaths as $parentPath) {
$repref =& $parentPath->findRepository($name);
if ($repref != null) {
$this->_repositories[] = $repref;
return $repref;
}
}
}
 
// Hack to return a string by reference; value retrieved at setup.php:414
$str = 'Unable to find repository "'.escape($name).'".';
$error =& $str;
return $error;
}
 
// }}}
 
// {{{ setServerIsWindows
//
// The server is running on Windows
 
function setServerIsWindows() {
$this->serverIsWindows = true;
 
// On Windows machines, use double quotes around command line parameters
$this->quote = '"';
 
// On Windows, semicolon separates path entries in a list rather than colon.
$this->pathSeparator = ';';
 
$this->fileUrlPrefix = 'file:///';
}
 
// }}}
 
// {{{ MultiViews
 
// useMultiViews
//
// Use MultiViews to access the repository
 
function useMultiViews($multiViewsIndex = 'browse') {
$this->multiViews = true;
$this->multiViewsIndex = $multiViewsIndex;
}
 
function getUseMultiViews() {
return $this->multiViews;
}
 
function getMultiViewsIndex() {
return $this->multiViewsIndex;
}
 
// }}}
 
// {{{ Enscript
 
// useEnscript
//
// Use Enscript to colourise listings
 
function useEnscript($before_1_6_3 = false) {
$this->useEnscript = true;
$this->useEnscriptBefore_1_6_3 = $before_1_6_3;
}
 
function getUseEnscript() {
return $this->useEnscript;
}
 
function getUseEnscriptBefore_1_6_3() {
return $this->useEnscriptBefore_1_6_3;
}
 
// }}}
 
// {{{ GeSHi
 
function setGeshiPath($path) {
$this->_setPath($this->geshiScript, $path, 'geshi.php');
}
 
function getGeshiScript() {
return $this->geshiScript;
}
 
// useGeshi
//
// Use GeSHi to colourise listings
function useGeshi() {
$this->useGeshi = true;
}
 
function getUseGeshi() {
return $this->useGeshi;
}
 
// }}}
 
// {{{ Parsedown
 
function setParsedownPath($path) {
$this->_setPath($this->parsedownScript, $path, 'Parsedown.php');
}
 
function getParsedownScript() {
return $this->parsedownScript;
}
 
// useParsedown
//
// Use Parsedown to render README.md
function useParsedown() {
$this->useParsedown = true;
}
 
function getUseParsedown() {
return $this->useParsedown;
}
 
// }}}
 
// {{{ Inline MIME Types
 
// inlineMimeTypes
//
// Specify MIME types to display inline in WebSVN pages
function addInlineMimeType($type) {
if (!in_array($type, $this->inlineMimeTypes)) {
$this->inlineMimeTypes[] = $type;
}
}
 
// }}}
 
// {{{ Show changed files by default on log.php
 
function setLogsShowChanges($enabled = true, $myrep = 0) {
if (empty($myrep)) {
$this->logsShowChanges = $enabled;
} else {
$repo =& $this->findRepository($myrep);
$repo->logsShowChanges = $enabled;
}
}
 
function logsShowChanges() {
return $this->logsShowChanges;
}
 
// }}}
 
// {{{ RSS
 
function setRssEnabled($enabled = true, $myrep = 0) {
if (empty($myrep)) {
$this->rss = $enabled;
} else {
$repo =& $this->findRepository($myrep);
$repo->setRssEnabled($enabled);
}
}
 
function isRssEnabled() {
return $this->rss;
}
 
function setRssCachingEnabled($enabled = true, $myrep = 0) {
if (empty($myrep)) {
$this->rssCaching = true;
} else {
$repo =& $this->findRepository($myrep);
$repo->setRssCachingEnabled($enabled);
}
}
 
function isRssCachingEnabled() {
return $this->rssCaching;
}
 
// Maximum number of entries in RSS feed
 
function setRssMaxEntries($max, $myrep = 0) {
if (empty($myrep)) {
$this->rssMaxEntries = $max;
} else {
$repo =& $this->findRepository($myrep);
$repo->setRssMaxEntries($max);
}
}
 
function getRssMaxEntries() {
return $this->rssMaxEntries;
}
 
function getHideRSS() {
return $this->rss;
}
 
// cacheRSS
//
// Enable caching of RSS feeds
 
function enableRSSCaching($myrep = 0) {
if (empty($myrep)) {
$this->rssCaching = true;
} else {
$repo =& $this->findRepository($myrep);
$repo->enableRSSCaching();
}
}
 
function getRSSCaching() {
return $this->rssCaching;
}
 
// }}}
 
// {{{ Downloads
 
// allowDownload
//
// Allow download of tarballs
 
function allowDownload($myrep = 0) {
if (empty($myrep)) {
$this->allowDownload = true;
} else {
$repo =& $this->findRepository($myrep);
$repo->allowDownload();
}
}
 
function disallowDownload($myrep = 0) {
if (empty($myrep)) {
$this->allowDownload = false;
} else {
$repo =& $this->findRepository($myrep);
$repo->disallowDownload();
}
}
 
function getAllowDownload() {
return $this->allowDownload;
}
 
function setTempDir($tempDir) {
$this->tempDir = $tempDir;
}
 
function getTempDir() {
if (empty($this->tempDir)) {
$this->tempDir = sys_get_temp_dir();
}
return $this->tempDir;
}
 
function setMinDownloadLevel($level, $myrep = 0) {
if (empty($myrep)) {
$this->minDownloadLevel = $level;
} else {
$repo =& $this->findRepository($myrep);
$repo->setMinDownloadLevel($level);
}
}
 
function getMinDownloadLevel() {
return $this->minDownloadLevel;
}
 
function addAllowedDownloadException($path, $myrep = 0) {
if ($path[strlen($path) - 1] != '/') {
$path .= '/';
}
 
if (empty($myrep)) {
$this->allowedExceptions[] = $path;
} else {
$repo =& $this->findRepository($myrep);
$repo->addAllowedDownloadException($path);
}
}
 
function addDisallowedDownloadException($path, $myrep = 0) {
if ($path[strlen($path) - 1] != '/') {
$path .= '/';
}
 
if (empty($myrep)) {
$this->disallowedExceptions[] = $path;
} else {
$repo =& $this->findRepository($myrep);
$repo->addDisallowedDownloadException($path);
}
}
 
function findException($path, $exceptions) {
foreach ($exceptions as $key => $exc) {
if (strncmp($exc, $path, strlen($exc)) == 0) {
return true;
}
}
 
return false;
}
 
// }}}
 
// {{{ getURL
//
// Get the URL to a path name based on the current config
 
function getURL($rep, $path, $op) {
list($base, $params) = $this->getUrlParts($rep, $path, $op);
$url = $base.'?';
foreach ($params as $k => $v) {
$url .= $k.'='.rawurlencode($v).'&amp;';
}
return $url;
}
 
// }}}
 
// {{{ getUrlParts
//
// Get the URL and parameters for a path name based on the current config
 
function getUrlParts($rep, $path, $op) {
$params = array();
 
if ($this->multiViews) {
$url = $_SERVER['SCRIPT_NAME'];
if (preg_match('|\.php$|i', $url)) {
// remove the .php extension
$url = substr($url, 0, -4);
}
 
if ($path && $path[0] != '/') {
$path = '/'.$path;
}
 
if (substr($url, -5) == 'index') {
$url = substr($url, 0, -5).$this->multiViewsIndex;
}
 
if ($op == 'index') {
$url .= '/';
} else if (is_object($rep)) {
$url .= '/'.$rep->getDisplayName().str_replace('%2F', '/', rawurlencode($path ?? ''));
 
if ($op && $op != 'dir' && $op != 'file') {
$params['op'] = $op;
}
}
 
} else {
switch ($op) {
case 'index':
$url = '.';
break;
 
case 'dir':
$url = 'listing.php';
break;
 
case 'revision':
$url = 'revision.php';
break;
 
case 'file':
$url = 'filedetails.php';
break;
 
case 'log':
$url = 'log.php';
break;
 
case 'diff':
$url = 'diff.php';
break;
 
case 'blame':
$url = 'blame.php';
break;
 
case 'form':
$url = 'form.php';
break;
 
case 'rss':
$url = 'rss.php';
break;
 
case 'dl':
$url = 'dl.php';
break;
 
case 'comp':
$url = 'comp.php';
break;
 
case 'search':
$url = 'search.php';
break;
}
 
if (is_object($rep) && $op != 'index') {
$params['repname'] = $rep->getDisplayName();
}
if (!empty($path)) {
$params['path'] = $path;
}
}
 
return array($url, $params);
}
 
// }}}
 
// {{{ Paths and Commands
 
// setPath
//
// Set the location of the given path
 
function _setPath(&$var, $path, $name, $params = '') {
if ($path == '') {
// Search in system search path. No check for existence possible
$var = $name;
} else {
$lastchar = substr($path, -1, 1);
$isDir = ($lastchar == DIRECTORY_SEPARATOR || $lastchar == '/' || $lastchar == '\\');
 
if (!$isDir) $path .= DIRECTORY_SEPARATOR;
 
if (($this->serverIsWindows && !file_exists($path.$name.'.exe')) || (!$this->serverIsWindows && !file_exists($path.$name))) {
echo 'Unable to find "'.$name.'" tool at location "'.$path.$name.'"';
exit;
}
 
// On a windows machine we need to put quotes around the
// entire command to allow for spaces in the path
if ($this->serverIsWindows) {
$var = '"'.$path.$name.'"';
} else {
$var = $path.$name;
}
}
 
// Append parameters
if ($params != '') $var .= ' '.$params;
}
 
// Define directory path to use for --config-dir parameter
function setSvnConfigDir($path) {
$this->_svnConfigDir = $path;
$this->_updateSvnCommand();
}
 
// Define flag to use --trust-server-cert parameter
function setTrustServerCert() {
$this->_svnTrustServerCert = true;
$this->_updateSvnCommand();
}
 
// Define the location of the svn command (e.g. '/usr/bin')
function setSvnCommandPath($path) {
$this->_svnCommandPath = $path;
$this->_updateSvnCommand();
}
 
// Define the location of the svnauthz command (e.g. '/usr/bin')
function setSvnAuthzCommandPath($path) {
$this->_setPath($this->svnAuthz, $path, 'svnauthz', 'accessof');
}
 
function _updateSvnCommand() {
$this->_setPath($this->svn, $this->_svnCommandPath, 'svn', '--non-interactive --config-dir '.$this->_svnConfigDir.($this->_svnTrustServerCert ? ' --trust-server-cert' : ''));
}
 
function getSvnCommand() {
return $this->svn;
}
 
function getSvnAuthzCommand() {
return $this->svnAuthz;
}
 
// setDiffPath
//
// Define the location of the diff command
 
function setDiffPath($path) {
$this->_setPath($this->diff, $path, 'diff');
}
 
function getDiffCommand() {
return $this->diff;
}
 
// setEnscriptPath
//
// Define the location of the enscript command
 
function setEnscriptPath($path) {
$this->_setPath($this->enscript, $path, 'enscript', '-q');
}
 
function getEnscriptCommand() {
return $this->enscript;
}
 
// setSedPath
//
// Define the location of the sed command
 
function setSedPath($path) {
$this->_setPath($this->sed, $path, 'sed');
}
 
function getSedCommand() {
return $this->sed;
}
 
// setTarPath
//
// Define the location of the tar command
 
function setTarPath($path) {
$this->_setPath($this->tar, $path, 'tar');
}
 
function getTarCommand() {
return $this->tar;
}
 
// setGzipPath
//
// Define the location of the GZip command
 
function setGzipPath($path) {
$this->_setPath($this->gzip, $path, 'gzip');
}
 
function getGzipCommand() {
return $this->gzip;
}
 
// setZipPath
//
// Define the location of the zip command
function setZipPath($path) {
$this->_setPath($this->zip, $path, 'zip');
}
 
function getZipPath() {
return $this->zip;
}
 
// setLocale
//
// Set the locale for PHP and all spawned processes
 
function setLocale($locale) {
$this->locale = $locale;
}
 
function getLocale() {
return $this->locale;
}
 
// setDefaultFileDlMode
//
// Define the default file download mode - one of [gzip, zip, plain]
function setDefaultFileDlMode($dlmode) {
if (in_array($dlmode, $this->validFileDlModes)) {
$this->defaultFileDlMode = $dlmode;
} else {
echo 'Setting default file download mode to an invalid value "'.$dlmode.'"';
exit;
}
}
 
function getDefaultFileDlMode() {
return $this->defaultFileDlMode;
}
 
// setDefaultDirectoryDlMode
//
// Define the default directory download mode - one of [gzip, zip]
function setDefaultDirectoryDlMode($dlmode) {
if (in_array($dlmode, $this->validDirectoryDlModes)) {
$this->defaultDirectoryDlMode = $dlmode;
} else {
echo 'Setting default directory download mode to an invalid value "'.$dlmode.'"';
exit;
}
}
 
function setDefaultFolderDlMode($dlmode) {
$this->setDefaultDirectoryDlMode($dlmode);
}
 
function getDefaultDirectoryDlMode() {
return $this->defaultDirectoryDlMode;
}
 
function getDefaultFolderDlMode() {
return $this->getDefaultDirectoryDlMode();
}
 
// Templates
 
function addTemplatePath($path) {
$lastchar = substr($path, -1, 1);
if ($lastchar != '/' && $lastchar != '\\') {
$path .= DIRECTORY_SEPARATOR;
}
 
if (!in_array($path, $this->templatePaths)) {
$this->templatePaths[] = $path;
}
}
 
function setTemplatePath($path, $myrep = null) {
$lastchar = substr($path, -1, 1);
if ($lastchar != '/' && $lastchar != '\\') {
$path .= DIRECTORY_SEPARATOR;
}
 
if ($myrep !== null) {
// fixed template for specific repository
$repo =& $this->findRepository($myrep);
$repo->setTemplatePath($path);
} else {
// for backward compatibility
if (in_array($path, $this->templatePaths)) {
array_splice($this->templatePaths, array_search($path, $this->templatePaths), 1);
}
array_unshift($this->templatePaths, $path);
}
}
 
function getTemplatePath() {
if (count($this->templatePaths) == 0) {
echo 'No template path added in config file';
exit;
}
if ($this->userTemplate !== false)
return $this->userTemplate;
else
return $this->templatePaths[0];
}
 
// }}}
 
function setDefaultLanguage($language) {
$this->defaultLanguage = $language;
}
 
function getDefaultLanguage() {
return $this->defaultLanguage;
}
 
function ignoreUserAcceptedLanguages() {
$this->ignoreAcceptedLanguages = true;
}
 
function useAcceptedLanguages() {
return !$this->ignoreAcceptedLanguages;
}
 
// {{{ Tab expansion functions
 
function expandTabsBy($sp, $myrep = 0) {
if (empty($myrep)) {
$this->spaces = $sp;
} else {
$repo =& $this->findRepository($myrep);
$repo->expandTabsBy($sp);
}
}
 
function getExpandTabsBy() {
return $this->spaces;
}
 
// }}}
 
// {{{ Bugtraq issue tracking
 
function setBugtraqEnabled($enabled, $myrep = 0) {
if (empty($myrep)) {
$this->bugtraq = $enabled;
} else {
$repo =& $this->findRepository($myrep);
$repo->setBugtraqEnabled($enabled);
}
}
 
function isBugtraqEnabled() {
return $this->bugtraq;
}
 
function setBugtraqProperties($message, $logregex, $url, $append = true, $myrep = null) {
$properties = array();
$properties['bugtraq:message'] = $message;
$properties['bugtraq:logregex'] = $logregex;
$properties['bugtraq:url'] = $url;
$properties['bugtraq:append'] = (bool)$append;
if ($myrep === null) {
$this->bugtraqProperties = $properties;
} else {
$repo =& $this->findRepository($myrep);
$repo->setBugtraqProperties($properties);
}
}
 
function getBugtraqProperties() {
return $this->bugtraqProperties;
}
 
// }}}
 
// {{{ Misc settings
 
function ignoreSvnMimeTypes() {
$this->ignoreSvnMimeTypes = true;
}
 
function getIgnoreSvnMimeTypes() {
return $this->ignoreSvnMimeTypes;
}
 
function ignoreWebSVNContentTypes() {
$this->ignoreWebSVNContentTypes = true;
}
 
function getIgnoreWebSVNContentTypes() {
return $this->ignoreWebSVNContentTypes;
}
 
function useAccessFile($file, $myrep = 0) {
if (empty($myrep)) {
if (is_readable($file)) {
if ($this->authz === null) {
$this->authz = new Authorization();
}
$this->authz->addAccessFile($file);
} else {
echo 'Unable to read access file "'.$file.'"';
exit;
}
} else {
$repo =& $this->findRepository($myrep);
$repo->useAccessFile($file);
}
}
 
function &getAuthz() {
return $this->authz;
}
 
function areRobotsBlocked() {
return $this->blockRobots;
}
 
function setBlockRobots($value = true) {
$this->blockRobots = $value;
}
 
function useTreeView() {
$this->treeView = true;
}
 
function getUseTreeView() {
return $this->treeView;
}
 
function useFlatView() {
$this->treeView = false;
}
 
function useTreeIndex($open) {
$this->flatIndex = false;
$this->openTree = $open;
}
 
function getUseFlatIndex() {
return $this->flatIndex;
}
 
function getOpenTree() {
return $this->openTree;
}
 
function setLoadAllRepos($flag) {
$this->loadAllRepos = $flag;
}
 
function showLoadAllRepos() {
return $this->loadAllRepos;
}
 
function setAlphabeticOrder($flag) {
$this->alphabetic = $flag;
}
 
function isAlphabeticOrder() {
return $this->alphabetic;
}
 
function showLastModInIndex() {
return $this->showLastModInIndex;
}
 
function setShowLastModInIndex($show) {
$this->showLastModInIndex = $show;
}
 
function showLastModInListing() {
return $this->showLastModInListing;
}
 
function setShowLastModInListing($show) {
$this->showLastModInListing = $show;
}
 
function showAgeInsteadOfDate() {
return $this->showAgeInsteadOfDate;
}
 
function setShowAgeInsteadOfDate($show) {
$this->showAgeInsteadOfDate = $show;
}
 
function showRepositorySelectionForm() {
return $this->_showRepositorySelectionForm;
}
 
function setShowRepositorySelectionForm($show) {
$this->_showRepositorySelectionForm = $show;
}
 
function getIgnoreWhitespacesInDiff() {
return $this->_ignoreWhitespacesInDiff;
}
 
function setIgnoreWhitespacesInDiff($ignore) {
$this->_ignoreWhitespacesInDiff = $ignore;
}
 
// Methods for storing version information for the command-line svn tool
 
function setSubversionVersion($subversionVersion) {
$this->subversionVersion = $subversionVersion;
}
 
function getSubversionVersion() {
return $this->subversionVersion;
}
 
function setSubversionMajorVersion($subversionMajorVersion) {
$this->subversionMajorVersion = $subversionMajorVersion;
}
 
function getSubversionMajorVersion() {
return $this->subversionMajorVersion;
}
 
function setSubversionMinorVersion($subversionMinorVersion) {
$this->subversionMinorVersion = $subversionMinorVersion;
}
 
function getSubversionMinorVersion() {
return $this->subversionMinorVersion;
}
 
// }}}
 
// {{{ Sort the repostories
//
// This function sorts the repositories by group name. The contents of the
// group are left in there original order, which will either be sorted if the
// group was added using the parentPath function, or defined for the order in
// which the repositories were included in the user's config file.
//
// Note that as of PHP 4.0.6 the usort command no longer preserves the order
// of items that are considered equal (in our case, part of the same group).
// The mergesort function preserves this order.
 
function sortByGroup() {
if (!empty($this->_repositories)) {
mergesort($this->_repositories, 'cmpGroups');
}
}
 
// }}}
 
// {{{ Change the name of the breadcrumb root-phrase to that of the current repo?
 
function setBreadcrumbRepoRootAsRepo($newValue) {
$this->breadcrumbRepoRootAsRepo = $newValue;
}
 
function getBreadcrumbRepoRootAsRepo() {
return $this->breadcrumbRepoRootAsRepo;
}
 
// }}}
}
/WebSVN/include/diff_inc.php
0,0 → 1,349
<?php
// WebSVN - Subversion repository viewing via the web using PHP
// Copyright (C) 2004-2006 Tim Armes
//
// 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; either version 2 of the License, or
// (at your option) any later version.
//
// 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; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// --
//
// diff_inc.php
//
// Diff to files
 
if (!defined('USE_AUTOLOADER')) {
@include_once 'Horde/String.php';
@include_once 'Horde/Text/Diff.php';
@include_once 'Horde/Text/Diff/Mapped.php';
@include_once 'Horde/Text/Diff/Engine/Native.php';
@include_once 'Horde/Text/Diff/Op/Base.php';
@include_once 'Horde/Text/Diff/Op/Copy.php';
@include_once 'Horde/Text/Diff/Op/Delete.php';
@include_once 'Horde/Text/Diff/Op/Add.php';
@include_once 'Horde/Text/Diff/Op/Change.php';
@include_once 'Horde/Text/Diff/Renderer.php';
@include_once 'Horde/Text/Diff/Renderer/Unified.php';
}
include_once 'include/diff_util.php';
 
$arrayBased = false;
$fileBased = false;
 
class ListingHelper {
var $_listing = array();
var $_index = 0;
var $_blockStart = false;
 
function _add($text1, $lineno1, $class1, $text2, $lineno2, $class2) {
$listing = &$this->_listing;
$index = &$this->_index;
 
$listvar = &$listing[$index];
$listvar['rev1diffclass'] = $class1;
$listvar['rev2diffclass'] = $class2;
 
$listvar['rev1line'] = $text1;
$listvar['rev2line'] = $text2;
 
$listvar['rev1lineno'] = $lineno1;
$listvar['rev2lineno'] = $lineno2;
$listvar['startblock'] = $this->_blockStart;
$this->_blockStart = false;
$index++;
}
 
function addDeletedLine($text, $lineno) {
$this->_add($text, $lineno, 'diffdeleted', '&nbsp;', '-', 'diffempty');
}
 
function addAddedLine($text, $lineno) {
$this->_add('&nbsp;', '-', 'diffempty', $text, $lineno, 'diffadded');
}
 
function addChangedLine($text1, $lineno1, $text2, $lineno2) {
$this->_add($text1, $lineno1, 'diffchanged', $text2, $lineno2, 'diffchanged');
}
 
// note that $text1 do not need to be equal $text2 if $ignoreWhitespace is true
function addLine($text1, $lineno1, $text2, $lineno2) {
$this->_add($text1, $lineno1, 'diff', $text2, $lineno2, 'diff');
}
 
function startNewBlock() {
$this->_blockStart = true;
}
 
function getListing() {
return $this->_listing;
}
}
 
function nextLine(&$obj) {
global $arrayBased, $fileBased;
if ($arrayBased) return array_shift($obj);
if ($fileBased) return fgets($obj);
return '';
}
 
function endOfFile(&$obj) {
global $arrayBased, $fileBased;
if ($arrayBased) return count($obj) == 0;
if ($fileBased) return feof($obj);
return true;
}
 
 
function getWrappedLineFromFile($file, $is_highlighted) {
$line = fgets($file);
if ($line === false) return false;
$line = toOutputEncoding($line);
if (!$is_highlighted) {
$line = escape($line);
}
$line = rtrim($line, "\n\r");
if (strip_tags($line) === '') $line = '&nbsp;';
return wrapInCodeTagIfNecessary($line);
}
 
function diff_result($all, $highlighted, $newtname, $oldtname, $obj, $ignoreWhitespace) {
$ofile = fopen($oldtname, 'r');
$nfile = fopen($newtname, 'r');
 
// Get the first real line
$line = nextLine($obj);
 
$index = 0;
$listingHelper = new ListingHelper();
 
$curoline = 1;
$curnline = 1;
 
$sensibleLineChanges = new SensibleLineChanges(new LineDiff($ignoreWhitespace));
 
while (!endOfFile($obj)) {
// Get the first line of this range
$oline = 0;
sscanf($line, '@@ -%d', $oline);
$line = substr($line, strpos($line, '+'));
$nline = 0;
sscanf($line, '+%d', $nline);
 
while ($curoline < $oline || $curnline < $nline) {
if ($curoline < $oline) {
$text1 = getWrappedLineFromFile($ofile, $highlighted);
$tmpoline = $curoline;
$curoline++;
} else {
$tmpoline = '?';
$text1 = '&nbsp';
}
 
if ($curnline < $nline) {
$text2 = getWrappedLineFromFile($nfile, $highlighted);
$tmpnline = $curnline;
$curnline++;
} else {
$tmpnline = '?';
$text2 = '&nbsp;';
}
 
if ($all) {
$listingHelper->addLine($text1, $tmpoline, $text2, $tmpnline);
}
}
 
if (!$all && $line !== false) {
$listingHelper->startNewBlock();
}
 
$fin = false;
while (!endOfFile($obj) && !$fin) {
$line = nextLine($obj);
if ($line === false || $line === '' || strncmp($line, '@@', 2) == 0) {
$sensibleLineChanges->addChangesToListing($listingHelper, $highlighted);
$fin = true;
} else {
$mod = $line[0];
$line = substr($line, 1);
 
switch ($mod) {
case '-':
$text = getWrappedLineFromFile($ofile, $highlighted);
$sensibleLineChanges->addDeletedLine($line, $text, $curoline);
$curoline++;
break;
 
case '+':
$text = getWrappedLineFromFile($nfile, $highlighted);
$sensibleLineChanges->addAddedLine($line, $text, $curnline);
$curnline++;
break;
 
default:
$sensibleLineChanges->addChangesToListing($listingHelper, $highlighted);
 
$text1 = getWrappedLineFromFile($ofile, $highlighted);
$text2 = getWrappedLineFromFile($nfile, $highlighted);
$listingHelper->addLine($text1, $curoline, $text2, $curnline);
 
$curoline++;
$curnline++;
 
break;
}
}
 
if (!$fin) {
$index++;
}
}
}
$sensibleLineChanges->addChangesToListing($listingHelper, $highlighted);
 
// Output the rest of the files
if ($all) {
while (!feof($ofile) || !feof($nfile)) {
$noneof = false;
 
$text1 = getWrappedLineFromFile($ofile, $highlighted);
if ($text1 !== false) {
$tmpoline = $curoline;
$curoline++;
$noneof = true;
} else {
$tmpoline = '-';
$text1 = '&nbsp;';
}
 
 
$text2 = getWrappedLineFromFile($nfile, $highlighted);
if ($text2 !== false) {
$tmpnline = $curnline;
$curnline++;
$noneof = true;
} else {
$tmpnline = '-';
$text2 = '&nbsp;';
}
 
if ($noneof) {
$listingHelper->addLine($text1, $tmpoline, $text2, $tmpnline);
}
 
}
}
 
fclose($ofile);
fclose($nfile);
 
return $listingHelper->getListing();
}
 
function command_diff($all, $ignoreWhitespace, $highlighted, $newtname, $oldtname, $newhlname, $oldhlname) {
global $config, $lang, $arrayBased, $fileBased;
 
$context = 5;
 
if ($all) {
// Setting the context to 0 makes diff generate the wrong line numbers!
$context = 1;
}
 
if ($ignoreWhitespace) {
$whitespaceFlag = ' -w';
} else {
$whitespaceFlag = '';
}
 
// Open a pipe to the diff command with $context lines of context:
$cmd = $config->diff.$whitespaceFlag.' -U '.$context.' "'.$oldtname.'" "'.$newtname.'"';
$diff = runCommand($cmd, true);
 
// Ignore the 3 header lines:
$line = array_shift($diff);
$line = array_shift($diff);
 
$arrayBased = true;
$fileBased = false;
 
if ($highlighted) {
$listing = diff_result($all, $highlighted, $newhlname, $oldhlname, $diff, $ignoreWhitespace);
} else {
$listing = diff_result($all, $highlighted, $newtname, $oldtname, $diff, $ignoreWhitespace);
}
 
return $listing;
}
 
function inline_diff($all, $ignoreWhitespace, $highlighted, $newtname, $oldtname, $newhlname, $oldhlname) {
global $arrayBased, $fileBased;
 
$context = 5;
if ($all) {
// Setting the context to 0 makes diff generate the wrong line numbers!
$context = 1;
}
 
// modify error reporting level to suppress deprecated/strict warning "Assigning the return value of new by reference"
$bckLevel = error_reporting();
$removeLevel = E_DEPRECATED;
$modLevel = $bckLevel & (~$removeLevel);
error_reporting($modLevel);
 
// Create the diff class
$fromLines = file($oldtname);
$toLines = file($newtname);
if (!$ignoreWhitespace) {
$diff = new Horde_Text_Diff('Native', array($fromLines, $toLines));
} else {
$whitespaces = array(' ', "\t", "\n", "\r");
$mappedFromLines = array();
foreach ($fromLines as $k => $line) {
$line = rtrim($line, "\n\r");
$fromLines[$k] = $line;
$mappedFromLines[] = str_replace($whitespaces, array(), $line);
}
$mappedToLines = array();
foreach ($toLines as $k => $line) {
$line = rtrim($line, "\n\r");
$toLines[$k] = $line;
$mappedToLines[] = str_replace($whitespaces, array(), $line);
}
$diff = new Horde_Text_Diff_Mapped('Native', array($fromLines, $toLines, $mappedFromLines, $mappedToLines));
}
$renderer = new Horde_Text_Diff_Renderer_Unified(array('leading_context_lines' => $context, 'trailing_context_lines' => $context));
$rendered = explode("\n", $renderer->render($diff));
 
// restore previous error reporting level
error_reporting($bckLevel);
 
$arrayBased = true;
$fileBased = false;
if ($highlighted) {
$listing = diff_result($all, $highlighted, $newhlname, $oldhlname, $rendered, $ignoreWhitespace);
} else {
$listing = diff_result($all, $highlighted, $newtname, $oldtname, $rendered, $ignoreWhitespace);
}
 
return $listing;
}
 
function do_diff($all, $ignoreWhitespace, $highlighted, $newtname, $oldtname, $newhlname, $oldhlname) {
if ((!$ignoreWhitespace ? class_exists('Horde_Text_Diff') : class_exists('Horde_Text_Diff_Mapped'))
&& class_exists('Horde_Text_Diff_Renderer_Unified')) {
return inline_diff($all, $ignoreWhitespace, $highlighted, $newtname, $oldtname, $newhlname, $oldhlname);
} else {
return command_diff($all, $ignoreWhitespace, $highlighted, $newtname, $oldtname, $newhlname, $oldhlname);
}
}
/WebSVN/include/diff_util.php
0,0 → 1,364
<?php
// WebSVN - Subversion repository viewing via the web using PHP
// Copyright (C) 2004-2006 Tim Armes
//
// 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; either version 2 of the License, or
// (at your option) any later version.
//
// 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; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// --
//
// diff_util.php
//
// help diff_inc.php to make sensible changes from added and deleted diff lines
// These lines are automatically paired and also inline diff is performed to show
// insertions/deletions on one line. diff_inc.php must have all Horde_Text_Diff
// requirements met (include_once statements).
 
// Interface for diffing function
class LineDiffInterface {
// similarity 1 means that strings are very close to each other
// 0 means totally different
function lineSimilarity($text1, $text2) {
assert(false);
}
 
// return array($left, $right) annotated with <ins> and <del>
function inlineDiff($text1, $highlighted1, $text2, $highlighted2, $highlighted) {
assert(false);
}
}
 
// Default line diffing function
class LineDiff extends LineDiffInterface {
 
private bool $ignoreWhitespace;
 
function __construct($ignoreWhitespace) {
$this->ignoreWhitespace = $ignoreWhitespace;
}
 
// {{{ levenshtein2
// levenshtein edit distance, on small strings use php function
// on large strings approximate distance using words
// computed by dynamic programming
function levenshtein2($str1, $str2) {
if (strlen($str1) < 255 && strlen($str2) < 255) {
return levenshtein($str1, $str2);
}
 
$l1 = explode(' ', $str1);
$l2 = explode(' ', $str2);
 
$n = count($l1);
$m = count($l2);
$d = array_fill(0, $n + 1, array_fill(0, $m + 1, 0));
 
for ($i = 1; $i < $n + 1; $i++) {
$d[$i][0] = $i;
}
for ($j = 1; $j < $m + 1; $j++) {
$d[0][$j] = $j;
}
 
for ($i = 1; $i < $n + 1; $i++) {
for ($j = 1; $j < $m + 1; $j++) {
$c = ($l1[$i - 1] == $l2[$j - 1]) ? 0 : strlen($l1[$i - 1]) + strlen($l2[$j - 1]);
$d[$i][$j] = min($d[$i - 1][$j] + 1, $d[$i][$j - 1] + 1, $d[$i - 1][$j - 1] + $c);
}
}
 
return $d[$n][$m];
}
// }}}
 
// {{{ lineSimilarity
function lineSimilarity($text1, $text2) {
$distance = $this->levenshtein2($text1, $text2);
return max(0.0, 1.0 - $distance / (strlen($text1) + strlen($text2) + 4));
}
// }}}
 
// {{{ tokenize whole line into words
// note that separators are returned as tokens of length 1
// and if $ignoreWhitespace is true, consecutive whitespaces are returned as one token
function tokenize($string, $highlighted, $ignoreWhitespace) {
$html = array('<' => '>', '&' => ';');
$whitespaces = array("\t","\n","\r",' ');
$separators = array('.','-','+','*','/','<','>','?','(',')','&','/','{','}','[',']',':',';');
$data = array();
$segment = '';
$segmentIsWhitespace = true;
$count = strlen($string);
for ($i = 0; $i < $count; $i++) {
$c = $string[$i];
if ($highlighted && array_key_exists($c, $html)) {
if ($segment != '') {
$data[] = $segment;
}
// consider html tags and entities as a single token
$endchar = $html[$c];
$segment = $c;
do {
$i++;
$c = $string[$i];
$segment .= $c;
} while ($c != $endchar && $i < $count - 1);
$data[] = $segment;
$segment = '';
$segmentIsWhitespace = false;
} else if (in_array($c, $separators) || (!$ignoreWhitespace && in_array($c, $whitespaces))) {
// if it is separator or whitespace and we do not consider consecutive whitespaces
if ($segment != '') {
$data[] = $segment;
}
$data[] = $c;
$segment = '';
$segmentIsWhitespace = true;
} else if (in_array($c, $whitespaces)) {
// if it is whitespace and we consider consecutive whitespaces as one token
if (!$segmentIsWhitespace) {
$data[] = $segment;
$segment = '';
$segmentIsWhitespace = true;
}
$segment .= $c;
} else {
// no separator or whitespace
if ($segmentIsWhitespace && $segment != '') {
$data[] = $segment;
$segment = '';
}
$segment .= $c;
$segmentIsWhitespace = false;
}
}
if ($segment != '') {
$data[] = $segment;
}
return $data;
}
// }}}
 
// {{{ lineDiff
function inlineDiff($text1, $highlighted1, $text2, $highlighted2, $highlighted) {
$whitespaces = array(' ', "\t", "\n", "\r");
 
$do_diff = true;
 
if ($text1 == '' || $text2 == '') {
$do_diff = false;
}
 
if ($this->ignoreWhitespace && (str_replace($whitespaces, array(), $text1) == str_replace($whitespaces, array(), $text2))) {
$do_diff = false;
}
 
// Exit gracefully if loading of Horde_Text_Diff failed
if (!class_exists('Horde_Text_Diff') || !class_exists('Horde_Text_Diff_Mapped')) {
$do_diff = false;
}
 
// Return highlighted lines without doing inline diff
if (!$do_diff) {
return array($highlighted1, $highlighted2);
}
 
$tokens1 = $this->tokenize($highlighted1, $highlighted, $this->ignoreWhitespace);
$tokens2 = $this->tokenize($highlighted2, $highlighted, $this->ignoreWhitespace);
 
if (!$this->ignoreWhitespace) {
$diff = new Horde_Text_Diff('Native', array($tokens1, $tokens2));
} else {
// we need to create mapped parts for MappedDiff
$mapped1 = array();
foreach ($tokens1 as $token) {
$mapped1[] = str_replace($whitespaces, array(), $token);
}
$mapped2 = array();
foreach ($tokens2 as $token) {
$mapped2[] = str_replace($whitespaces, array(), $token);
}
$diff = new Horde_Text_Diff_Mapped('Native', array($tokens1, $tokens2, $mapped1, $mapped2));
}
 
// now, get the diff and annotate text
$edits = $diff->getDiff();
 
$line1 = '';
$line2 = '';
foreach ($edits as $edit) {
if ($edit instanceof Horde_Text_Diff_Op_Copy) {
$line1 .= implode('', $edit->orig);
$line2 .= implode('', $edit->final);
} else if ($edit instanceof Horde_Text_Diff_Op_Delete) {
$line1 .= '<del>'.implode('', $edit->orig).'</del>';
} else if ($edit instanceof Horde_Text_Diff_Op_Add) {
$line2 .= '<ins>'.implode('', $edit->final).'</ins>';
} else if ($edit instanceof Horde_Text_Diff_Op_Change) {
$line1 .= '<del>'.implode('', $edit->orig).'</del>';
$line2 .= '<ins>'.implode('', $edit->final).'</ins>';
} else {
assert(false);
}
}
return array($line1, $line2);
}
// }}}
}
 
// Class for computing sensibly added/deleted block of lines.
class SensibleLineChanges {
var $_added = array();
var $_deleted = array();
var $_lineDiff = null;
 
function __construct($lineDiff) {
$this->_lineDiff = $lineDiff;
}
 
function addDeletedLine($text, $highlighted_text, $lineno) {
$this->_deleted[] = array($text, $highlighted_text, $lineno);
}
 
function addAddedLine($text, $highlighted_text, $lineno) {
$this->_added[] = array($text, $highlighted_text, $lineno);
}
 
// this function computes simple match - first min(deleted,added) lines are marked as changed
// it is intended to be run instead of _computeBestMatching if the diff is too big
function _computeFastMatching($n, $m) {
$result = array();
$q = 0;
while ($q < $n && $q < $m) {
$result[] = array($this->_deleted[$q], $this->_added[$q]);
$q++;
}
while ($q < $n) {
$result[] = array($this->_deleted[$q], null);
$q++;
}
while ($q < $m) {
$result[] = array(null, $this->_added[$q]);
$q++;
}
return $result;
}
 
// {{{ _computeBestMatching
// dynamically compute best matching
// note that this is O(n*m) * O(line similarity)
function _computeBestMatching() {
$n = count($this->_deleted);
$m = count($this->_added);
 
// if the computation will be slow, just run fast algorithm
if ($n * $m > 10000) {
return $this->_computeFastMatching($n, $m);
}
 
// dyn[$i][$j] holds best sum of similarities we can obtain if we match
// first $i deleted lines and first $j added lines
$dyn = array_fill(0, $n + 1, array_fill(0, $m + 1, 0.0));
// backlinks, so we can reconstruct best layout easily
$back = array_fill(0, $n + 1, array_fill(0, $m + 1, -1));
 
// if there is no similarity, prefer adding/deleting lines
$value_del = 0.1;
$value_add = 0.1;
 
// initialize arrays
for ($i = 1; $i <= $n; $i++) {
$back[$i][0] = 0;
$dyn[$i][0] = $value_del * $i;
}
for ($j = 1; $j <= $m; $j++) {
$back[0][$j] = 1;
$dyn[0][$j] = $value_add * $j;
}
 
// main dynamic programming
for ($i = 1; $i <= $n; $i++) {
for ($j = 1; $j <= $m; $j++) {
$best = - 1.0;
$b = -1;
if ($dyn[$i - 1][$j] + $value_del >= $best) {
$b = 0;
$best = $dyn[$i - 1][$j] + $value_del;
}
if ($dyn[$i][$j - 1] + $value_add >= $best) {
$b = 1;
$best = $dyn[$i][$j - 1] + $value_add;
}
$sim = $this->_lineDiff->lineSimilarity($this->_deleted[$i - 1][0], $this->_added[$j - 1][0]);
if ($dyn[$i - 1][$j - 1] + $sim >= $best) {
$b = 2;
$best = $dyn[$i - 1][$j - 1] + $sim;
}
$back[$i][$j] = $b;
$dyn[$i][$j] = $best;
}
}
 
// compute layout for best result
$i = $n;
$j = $m;
$result = array();
 
while ($i + $j >= 1) {
switch($back[$i][$j]) {
case 2: array_push($result, array($this->_deleted[$i - 1], $this->_added[$j - 1]));
$i--;
$j--;
break;
case 1: array_push($result, array(null, $this->_added[$j - 1]));
$j--;
break;
case 0: array_push($result, array($this->_deleted[$i - 1], null));
$i--;
break;
default:
assert(false);
}
}
return array_reverse($result);
}
// }}}
 
// {{{ addChangesToListing
// add computed changes to the listing
function addChangesToListing(&$listingHelper, $highlighted) {
$matching = $this->_computeBestMatching();
foreach ($matching as $change) {
if ($change[1] == null) {
// deleted -- preserve original highlighted text
$listingHelper->addDeletedLine($change[0][1], $change[0][2]);
} else if ($change[0] == null) {
// added -- preserve original highlighted text
$listingHelper->addAddedLine($change[1][1], $change[1][2]);
} else {
// this is fully changed line, make inline diff
$diff = $this->_lineDiff->inlineDiff($change[0][0], $change[0][1], $change[1][0], $change[1][1], $highlighted);
$listingHelper->addChangedLine($diff[0], $change[0][2], $diff[1], $change[1][2]);
}
}
$this->clear();
}
// }}}
 
function clear() {
$this->_added = array();
$this->_deleted = array();
}
}
 
/WebSVN/include/distconfig.php
0,0 → 1,528
<?php
// WebSVN - Subversion repository viewing via the web using PHP
// Copyright (C) 2004-2006 Tim Armes
//
// 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; either version 2 of the License, or
// (at your option) any later version.
//
// 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; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// --
//
// config.php
//
// Configuration parameters
 
// --- FOLLOW THE INSTRUCTIONS BELOW TO CONFIGURE YOUR SETUP ---
 
// {{{ PLATFORM CONFIGURATION ---
 
// Configure a UTF-8 aware locale to properly convert bytes to characters.
// Otherwise files and directories with non-ASCII encoding are deemed to fail
// with native commands.
// $config->setLocale('C.UTF-8');
 
// Configure the path for Subversion to use for --config-dir
// (e.g. if accepting certificates is required when using repositories via https)
// $config->setSvnConfigDir('/tmp/websvn');
 
// Configure these lines if your commands aren't on your path.
//
// $config->setSvnCommandPath('/path/to/svn/command/'); // e.g. c:\\program files\\subversion\\bin
// $config->setSvnAuthzCommandPath('/path/to/svnauthz/command/'); // e.g. c:\\program files\\subversion\\bin\tools
// $config->setDiffPath('/path/to/diff/command/');
 
// For syntax colouring, if option enabled...
// $config->setEnscriptPath('/path/to/enscript/command/');
// $config->setSedPath('/path/to/sed/command/');
 
// For delivered tarballs, if option enabled...
// $config->setTarPath('/path/to/tar/command/');
 
// For delivered GZIP'd files and tarballs, if option enabled...
// $config->setGZipPath('/path/to/gzip/command/');
 
// download directory/file zipped ...
// $config->setZipPath('/path/to/zip/command/');
 
// Uncomment this line to trust server certificates
// This may useful if you use self-signed certificates and have no chance to accept the certificate once via cli
// $config->setTrustServerCert();
 
// }}}
 
// {{{ REPOSITORY SETUP ---
 
// There are 2 methods for defining the repositiories available on the system.
// Either you list them by hand, in which case you can give each one the name of
// your choice, or you use the parent path function, in which case the name of
// the directory is used as the repository name.
//
// In all cases, you may optionally supply a group name to the repositories.
// This is useful in the case that you need to separate your projects. Grouped
// repositories are referred to using the convention GroupName.RepositoryName
//
// You may also optionally specify the URL that clients should use to check out
// a working copy. If used, it must be specified after the group, username, and
// password; if these arguments are not needed, then pass null instead. Consult
// the WebSvnConfig class in include/configclass.php for function details.
//
// Performance is much better on local repositories (e.g. accessed by file://).
// However, you can also provide an interface onto a remote repository. In this
// case you should supply the username and password needed to access it.
//
// To configure the repositories by hand, copy the appropriate line below,
// uncomment it and replace the name and URL of your repository.
 
// Local repositories (without and with optional group):
// Note that the local URL to the repository depends on your platform:
// Unix-like: file:///path/to/rep
// Windows: file:///c:/svn/proj
//
// $config->addRepository('NameToDisplay', 'local URL');
// $config->addRepository('NameToDisplay', 'local URL', 'group');
//
// Remote repositories (without and with optional group):
// A remote URL looks like http://domain.tld/path/to/rep
//
// $config->addRepository('NameToDisplay', 'remote URL', null, 'username', 'password');
// $config->addRepository('NameToDisplay', 'remote URL', 'group', 'username', 'password');
//
// Display Part of a repository as if it was a repository.
//
// Local repositories (without and with optional group):
//
// $config->addRepositorySubpath('NameToDisplay', 'local URL', 'subpath');
// $config->addRepositorySubpath('NameToDisplay', 'local URL', 'subpath', 'group');
//
// Remote repositories (without and with optional group):
//
// $config->addRepositorySubpath('NameToDisplay', 'remote URL', 'subpath', null, 'username', 'password');
// $config->addRepositorySubpath('NameToDisplay', 'remote URL', 'subpath', 'group', 'username', 'password');
//
// To use the parent path method (without and with optional group), uncomment the next line
// and replace the path with your one. You can call the function several times if you have several parent paths.
// Note that in this case the path is a filesystem path and depends on your platform:
// Unix-like: /path/to/parent
// Windows: c:\\svn
//
// $config->parentPath('filesystem path');
// $config->parentPath('filesystem path', 'group');
//
// To exclude a repository from being added by the parentPath method uncomment the next line
// and replace the path with your one. You can call the function several times if you have several paths to exclude.
//
// $config->addExcludedPath('filesystem path of excluded rep');
//
// To add only a subset of repositories specified by the parent path you can call the function with a pattern.
//
// $config->parentPath('filesystem path', 'group', '/^beginwith/');
 
// }}}
 
// {{{ LOOK AND FEEL ---
//
// Add custom template paths or comment out templates to modify the list of user selectable templates.
// The first added template serves as a default.
 
$config->addTemplatePath($locwebsvnreal.'/templates/calm/');
$config->addTemplatePath($locwebsvnreal.'/templates/BlueGrey/');
$config->addTemplatePath($locwebsvnreal.'/templates/Elegant/');
 
// You may also specify a default template by uncommenting and changing the following line as necessary.
// If no default template is set the first added template is used.
 
// $config->setTemplatePath($locwebsvnreal.'/templates/Elegant/');
 
// You may also specify a per repository fixed template by uncommenting and changing the following
// line as necessary. Use the convention 'groupname.myrep' if your repository is in a group.
 
// $config->setTemplatePath($locwebsvnreal.'/templates/Elegant/', 'myrep');
 
// The index page containing the projects may either be displayed as a flat view (the default),
// where grouped repositories are displayed as 'GroupName.RepName' or as a tree view.
// In the case of a tree view, you may choose whether the entire tree is open by default.
 
// $config->useTreeIndex(false); // Tree index, closed by default
// $config->useTreeIndex(true); // Tree index, open by default
 
// By default, WebSVN displays a tree view onto the current directory. You can however
// choose to display a flat view of the current directory only, which may make the display
// load faster. Uncomment this line if you want that.
 
// $config->useFlatView();
 
// By default, WebSVN displays subdirectories first and than the files of a directory,
// both alphabetically sorted.
// To use alphabetic order independent of directories and files uncomment this line.
 
// $config->setAlphabeticOrder(true);
 
// By default, WebSVN loads parent path directories and then on user click other,
// This options loads the entire directory in one go and allows to browse without delay.
// By default all will be collapsed to root directory and can be expanded.
// The performance will be impacted as it takes time to load up all the things in the
// repository. Once loaded directory exapansion is instantaneous.
// The alphabetical order is applied to all directory and files.
// This means that grouping of all dirs together and all files together is NOT supported currently!
// The files and directories are shown as is with a mixture of files and folders.
 
// $config->setLoadAllRepos(true);
 
// By default, WebSVN displays the information of the last modification
// (revision, age and author) for each repository in an extra column.
// To disable that uncomment this line.
 
// $config->setShowLastModInIndex(false);
 
// By default, WebSVN displays the information of the last modification
// (revision, age and author) for each file and directory in an extra column.
// To disable that uncomment this line.
 
// $config->setShowLastModInListing(false);
 
// By default, WebSVN displays the age of the last modification.
// Alternativly the date of the last modification can be shown.
// To show dates instead of ages uncomment this line.
 
// $config->setShowAgeInsteadOfDate(false);
 
// By default, WebSVN displays the a form to select an other repository.
// If you have a lot of repositories this slows done the script considerably.
// To disable that uncomment this line.
 
// $config->setShowRepositorySelectionForm(false);
 
// By default, WebSVN does not ignore whitespaces when showing diffs.
// To enable ignoring whitespaces in diffs per default uncomment this line.
 
// $config->setIgnoreWhitespacesInDiff(true);
 
// }}}
 
// {{{ LANGUAGE SETUP ---
 
// Set the default language. If you want English then don't do anything here.
//
// $config->setDefaultLanguage('en');
 
// Ignore the user supplied accepted languages to choose reasonable default language.
// If you want to force the default language - regardless of the client - uncomment the following line.
//
// $config->ignoreUserAcceptedLanguages();
 
// }}}
 
// {{{ MULTIVIEWS ---
 
// Uncomment this line if you want to use MultiView to access the repository by, for example:
//
// http://servername/browse/repname/path/in/repository
//
// Note: The websvn directory will need to have Multiviews turned on in Apache, and you'll need to configure browse.php
 
// $config->useMultiViews();
 
// }}}
 
// {{{ ACCESS RIGHTS ---
 
// Uncomment this line if you want to use your Subversion access file to control access
// rights via WebSVN. For this to work, you'll need to set up the same Apache based authentication
// to the WebSVN (or browse) directory as you have for Subversion itself. More information can be
// found in install.txt
 
// $config->useAccessFile('/path/to/accessfile'); // Global access file
 
// You may also specify a per repository access file by uncommenting and copying the following
// line as necessary. Use the convention 'groupname.myrep' if your repository is in a group.
 
// $config->useAccessFile('/path/to/accessfile', 'myrep'); // Access file for myrep
 
// Uncomment this line if you want to prevent search bots to index the WebSVN pages.
 
// $config->setBlockRobots();
 
// }}}
 
// {{{ FILE CONTENT ---
//
// You may wish certain file types to be GZIP'd and delieved to the user when clicked apon.
// This is useful for binary files and the like that don't display well in a browser window!
// Copy, uncomment and modify this line for each extension to which this rule should apply.
// (Don't forget the . before the extension. You don't need an index between the []'s).
// If you'd rather that the files were delivered uncompressed with the associated MIME type,
// then read below.
//
// $zipped[] = '.dll';
 
// Subversion controlled files have an svn:mime-type property that can
// be set on a file indicating its mime type. By default binary files
// are set to the generic appcliation/octet-stream, and other files
// don't have it set at all. WebSVN also has a built-in list of
// associations from file extension to MIME content type. (You can
// view this list in setup.php).
//
// Determining the content-type: By default, if the svn:mime-type
// property exists and is different from application/octet-stream, it
// is used. Otherwise, if the built-in list has a contentType entry
// for the extension of the file, that is used. Otherwise, if the
// svn:mime-type property exists has the generic binary value of
// application/octet-stream, the file will be served as a binary
// file. Otherwise, the file will be brought up as ASCII text in the
// browser window (although this text may optionally be colourised.
// See below).
//
// Uncomment this if you want to ignore any svn:mime-type property on your
// files.
//
// $config->ignoreSvnMimeTypes();
//
// Uncomment this if you want skip WebSVN's custom mime-type handling
//
// $config->ignoreWebSVNContentTypes();
//
// Following the examples below, you can add new associations, modify
// the default ones or even delete them entirely (to show them in
// ASCII via WebSVN).
 
// $contentType['.c'] = 'text/plain'; // Create a new association
// $contentType['.doc'] = 'text/plain'; // Modify an existing one
// unset($contentType['.m']); // Remove a default association
 
// If you want to selectively override one or more MIME types to display inline
// (e.g., the svn:mime-type property is something like text/plain or text/xml, or
// the file extension matches an entry in $contentType), you can choose to ignore
// one or more specific MIME types. This approach is finer-grained than ignoring
// all svn:mime-type properties, and displaying matching files inline such that
// they are highlighted correctly. (Regular expression matching is used.)
 
$config->addInlineMimeType('text/plain');
// $config->addInlineMimeType('text/*');
 
// }}}
 
// {{{ TARBALLS ---
 
// You need tar and gzip installed on your system. Set the paths above if necessary
//
// Uncomment the line below to offer a tarball download option across all your
// repositories.
//
// $config->allowDownload();
//
// Set download modes
// $config->setDefaultFileDlMode('plain');
// $config->setDefaultDirectoryDlMode('gzip');
//
// To change the global option for individual repositories, uncomment and replicate
// the appropriate line below (replacing 'myrep' with the name of the repository).
// Use the convention 'groupname.myrep' if your repository is in a group.
 
// $config->allowDownload('myrep'); // Specifically allow downloading for 'myrep'
// $config->disallowDownload('myrep'); // Specifically disallow downloading for 'myrep'
 
// You can also choose the minimum directory level from which you'll allow downloading.
// A value of zero will allow downloading from the root. 1 will allow downloding of directories
// in the root, etc.
//
// If your project is arranged with trunk, tags and branches at the root level, then a value of 2
// would allow the downloading of directories within branches/tags while disallowing the download
// of the entire branches or tags directories. This would also stop downloading of the trunk, but
// see after for path exceptions.
//
// Change the line below to set the download level across all your repositories.
 
$config->setMinDownloadLevel(2);
 
// To change the level for individual repositories, uncomment and replicate
// the appropriate line below (replacing 'myrep' with the name of the repository).
// Use the convention 'groupname.myrep' if your repository is in a group.
 
// $config->setMinDownloadLevel(2, 'myrep');
 
// Finally, you may add or remove certain directories (and their contents) either globally
// or on a per repository basis. Uncomment and copy the following lines as necessary. Note
// that the these are searched in the order than you give them until a match is made (with the
// exception that all the per repository exceptions are tested before the global ones). This means
// that you must disallow /a/b/c/ before you allow /a/b/ otherwise the allowed match on /a/b/ will
// stop any further searching, thereby allowing downloads on /a/b/c/.
 
// Global exceptions possibilties:
//
// $config->addAllowedDownloadException('/path/to/allowed/directory/');
// $config->addDisAllowedDownloadException('/path/to/disallowed/directory/');
//
// Per repository exception possibilties:
// Use the convention 'groupname.myrep' if your repository is in a group.
//
// $config->addAllowedDownloadException('/path/to/allowed/directory/', 'myrep');
// $config->addDisAllowedDownloadException('/path/to/disallowed/directory/', 'myrep');
 
// }}}
 
// {{{ COLOURISATION ---
 
// Uncomment this line if you want to use Enscript to colourise your file listings
//
// You'll need Enscript version 1.6 or higher AND Sed installed to use this feature.
// Set the path above.
//
// If you have version 1.6.3 or newer use the following line.
//
// $config->useEnscript();
//
// If you have version 1.6.2 or older use the following line.
//
// $config->useEnscript(true);
 
// Enscript need to be told what the contents of a file are so that it can be colourised
// correctly. WebSVN includes a predefined list of mappings from file extension to Enscript
// file type (viewable in setup.php).
//
// Here you should add and other extensions not already listed or redefine the default ones. eg:
//
// $extEnscript['.pas'] = 'pascal';
//
// Note that extensions are case sensitive.
 
// Uncomment this line if you want to use GeSHi to colourise your file listings
//
// $config->useGeshi();
// $config->setGeshiPath('/usr/share/php-geshi'); // optional. Use if you have Geshi installed without PEAR/Composer
 
// GeSHi need to be told what the contents of a file are so that it can be colourised
// correctly. WebSVN includes a predefined list of mappings from file extension to GeSHi
// languages (viewable in setup.php).
//
// Here you should add and other extensions not already listed or redefine the default ones. eg:
//
// $extGeshi['pascal'] = array('p', 'pas');
//
// Note that extensions are case sensitive.
 
// }}}
 
// {{{ Markdown Render
 
// Uncomment this line if you want to enable Markdown Rendering of README.md file in the path.
// You will need the Parsedown.php (https://github.com/erusev/parsedown) library for this to work.
// This will look for README.md file on the path and render it.
// The name of "README.md" isn't configurable for now to simply follow GitHub's conventions.
 
// $config->useParsedown();
// $config->setParsedownPath('/usr/share/php/Parsedown/'); // optional. Use if you have Parsedown installed without PEAR/Composer
 
// }}}
 
// {{{ RSSFEED ---
 
// Uncomment this line to hide the RSS feed links across all repositories
 
// $config->setRssEnabled(false);
 
// To override the global setting for individual repositories, uncomment and replicate
// the appropriate line below (replacing 'myrep' with the name of the repository).
// Use the convention 'groupname.myrep' if your repository is in a group.
 
// $config->setRssEnabled(false, 'myrep');
// $config->setRssEnabled(true, 'myrep');
 
// Uncomment this line to enable caching RSS feeds across all repositories
// This may create a large number of cache files which are currently not garbaged automatically
 
// $config->setRssCachingEnabled(true);
 
// To override the global setting for individual repositories, uncomment and replicate
// the appropriate line below (replacing 'myrep' with the name of the repository).
// Use the convention 'groupname.myrep' if your repository is in a group.
 
// $config->setRssCachingEnabled(true, 'myrep');
// $config->setRssCachingEnabled(false, 'myrep');
 
// Uncomment this line to change the maximum number of RSS entries to display across all repositories
 
// $config->setRssMaxEntries(50);
 
// To override the global setting for individual repositories, uncomment and replicate
// the line below (replacing 'myrep' with the name of the repository).
// Use the convention 'groupname.myrep' if your repository is in a group.
 
// $config->setRssMaxEntries(50, 'myrep');
 
// }}}
 
// {{{ SHOW CHANGED FILES IN LOG ---
 
// Uncomment this line to show changed files on log.php by default. The normal
// behavior is to do this only if the "Show changed files" link is clicked. This
// setting reverses the default action but still allows hiding changed files.
 
// $config->setLogsShowChanges(true);
 
// To override the global setting for individual repositories, uncomment and replicate
// the appropriate line below (replacing 'myrep' with the name of the repository).
// Use the convention 'groupname.myrep' if your repository is in a group.
 
// $config->setLogsShowChanges(true, 'myrep');
// $config->setLogsShowChanges(false, 'myrep');
 
// }}}
 
// {{{ BUGTRAQ ---
 
// Uncomment this line to use bugtraq: properties to show links to your BugTracker
// from log messages.
 
// $config->setBugtraqEnabled(true);
 
// To override the global setting for individual repositories, uncomment and replicate
// the appropriate line below (replacing 'myrep' with the name of the repository).
// Use the convention 'groupname.myrep' if your repository is in a group.
 
// $config->setBugtraqEnabled(true, 'myrep');
// $config->setBugtraqEnabled(false, 'myrep');
 
// Usually the information to extract the bugtraq information and generate links are
// stored in SVN properties starting with 'bugtraq:':
// namely 'bugtraq:message', 'bugtraq:logregex', 'bugtraq:url' and 'bugtraq:append'.
// To override the SVN properties globally or for individual repositories, uncomment
// the appropriate line below (replacing 'myrep' with the name of the repository).
 
// $config->setBugtraqProperties('bug #%BUGID%', 'issues? (\d+)([, ] *(\d+))*'."\n".'(\d+)', 'http://www.example.com/issues/show_bug.cgi?id=%BUGID%', false);
// $config->setBugtraqProperties('bug #%BUGID%', 'issues? (\d+)([, ] *(\d+))*'."\n".'(\d+)', 'http://www.example.com/issues/show_bug.cgi?id=%BUGID%', false, 'myrep');
 
// }}}
 
// {{{ MISCELLANEOUS ---
 
// Comment out this if you don't have the right to use it. Be warned that you may need it however!
set_time_limit(0);
 
// Change the line below to specify a temporary directory other than the one PHP uses.
 
// $config->setTempDir('temp');
 
// Number of spaces to expand tabs to in diff/listing view across all repositories
 
$config->expandTabsBy(8);
 
// To override the global setting for individual repositories, uncomment and replicate
// the line below (replacing 'myrep' with the name of the repository).
// Use the convention 'groupname.myrep' if your repository is in a group.
 
// $config->expandTabsBy(3, 'myrep'); // Expand Tabs by 3 for repository 'myrep'
 
// Change the name of the breadcrumb root-phrase to that of the current repo?
// $config->setBreadcrumbRepoRootAsRepo(true);
 
// }}}
/WebSVN/include/header
1,7 → 1,5
# vim:et:ts=3:sts=3:sw=3:fdm=marker:
 
// WebSVN - Subversion repository viewing via the web using PHP
// Copyright © 2004-2006 Tim Armes, Matt Sicker
// Copyright (C) 2004-2006 Tim Armes
//
// 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
10,12 → 8,12
//
// 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
// 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; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// --
//
/WebSVN/include/setup.php
0,0 → 1,620
<?php
// WebSVN - Subversion repository viewing via the web using PHP
// Copyright (C) 2004-2006 Tim Armes
//
// 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; either version 2 of the License, or
// (at your option) any later version.
//
// 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; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// --
//
// setup.php
//
// Global setup
 
// --- DON'T CHANGE THIS FILE ---
//
// User changes should be done in config.php
 
// Include the configuration class
require_once 'include/configclass.php';
 
// Register Composer autoloader if available
if (file_exists(__DIR__ . '/../vendor/autoload.php')) {
require_once __DIR__ . '/../vendor/autoload.php';
define('USE_AUTOLOADER', true);
}
 
// Create the config
$config = new WebSvnConfig();
 
if (DIRECTORY_SEPARATOR == '\\') {
$config->setServerIsWindows();
}
 
// Set up locwebsvnhttp
// Note: we will use nothing in MultiViews mode so that the URLs use the root
// directory by default.
if (empty($locwebsvnhttp)) {
$locwebsvnhttp = defined('WSVN_MULTIVIEWS') ? '' : '.';
}
if (empty($locwebsvnreal)) {
$locwebsvnreal = '.';
}
 
$vars['locwebsvnhttp'] = $locwebsvnhttp;
 
// {{{ Content Types
// Set up the default content-type extension handling
 
$contentType = array(
'.dwg' => 'application/acad', // AutoCAD Drawing files
'.arj' => 'application/arj',
'.ccad' => 'application/clariscad', // ClarisCAD files
'.drw' => 'application/drafting', // MATRA Prelude drafting
'.dxf' => 'application/dxf', // DXF (AutoCAD)
'.xls' => 'application/excel', // Microsoft Excel
'.unv' => 'application/i-deas', //SDRC I-DEAS files
'.igs' => 'application/iges', // IGES graphics format
'.iges' => 'application/iges', // IGES graphics format
'.hqx' => 'application/mac-binhex40', // Macintosh BinHex format
'.word' => 'application/msword', // Microsoft Word
'.w6w' => 'application/msword', // Microsoft Word
'.doc' => 'application/msword', // Microsoft Word
'.wri' => 'application/mswrite', // Microsoft Write
'.bin' => 'application/octet-stream', // Uninterpreted binary
'.exe' => 'application/x-msdownload', // Windows EXE
'.oda' => 'application/oda',
'.pdf' => 'application/pdf', // PDF (Adobe Acrobat)
'.ai' => 'application/postscript', // PostScript
'.ps' => 'application/postscript', // PostScript
'.eps' => 'application/postscript', // PostScript
'.prt' => 'application/pro_eng', // PTC Pro/ENGINEER
'.part' => 'application/pro_eng', // PTC Pro/ENGINEER
'.rtf' => 'application/rtf', // Rich Text Format
'.set' => 'application/set', // SET (French CAD standard)
'.stl' => 'application/sla', // Stereolithography
'.sol' => 'application/solids', // MATRA Prelude Solids
'.stp' => 'application/STEP', // ISO-10303 STEP data files
'.step' => 'application/STEP', // ISO-10303 STEP data files
'.vda' => 'application/vda', // VDA-FS Surface data
'.dir' => 'application/x-director', // Macromedia Director
'.dcr' => 'application/x-director', // Macromedia Director
'.dxr' => 'application/x-director', // Macromedia Director
'.mif' => 'application/x-mif', // FrameMaker MIF Format
'.csh' => 'application/x-csh', // C-shell script
'.dvi' => 'application/x-dvi', // TeX DVI
'.gz' => 'application/gzip', // GNU Zip
'.gzip' => 'application/gzip', // GNU Zip
'.hdf' => 'application/x-hdf', // ncSA HDF Data File
'.latex' => 'application/x-latex', // LaTeX source
'.nc' => 'application/x-netcdf', // Unidata netCDF
'.cdf' => 'application/x-netcdf', // Unidata netCDF
'.sit' => 'application/x-stuffit', // Stiffut Archive
'.tcl' => 'application/x-tcl', // TCL script
'.texinfo' => 'application/x-texinfo', // Texinfo (Emacs)
'.texi' => 'application/x-texinfo', // Texinfo (Emacs)
'.t' => 'application/x-troff', // Troff
'.tr' => 'application/x-troff', // Troff
'.roff' => 'application/x-troff', // Troff
'.man' => 'application/x-troff-man', // Troff with MAN macros
'.me' => 'application/x-troff-me', // Troff with ME macros
'.ms' => 'application/x-troff-ms', // Troff with MS macros
'.src' => 'application/x-wais-source', // WAIS source
'.bcpio' => 'application/x-bcpio', // Old binary CPIO
'.cpio' => 'application/x-cpio', // POSIX CPIO
'.gtar' => 'application/x-gtar', // GNU tar
'.shar' => 'application/x-shar', // Shell archive
'.sv4cpio' => 'application/x-sv4cpio', // SVR4 CPIO
'.sv4crc' => 'application/x-sv4crc', // SVR4 CPIO with CRC
'.tar' => 'application/x-tar', // 4.3BSD tar format
'.ustar' => 'application/x-ustar', // POSIX tar format
'.hlp' => 'application/x-winhelp', // Windows Help
'.zip' => 'application/zip', // ZIP archive
 
'.au' => 'audio/basic', // Basic audio (usually m-law)
'.snd' => 'audio/basic', // Basic audio (usually m-law)
'.aif' => 'audio/x-aiff', // AIFF audio
'.aiff' => 'audio/x-aiff', // AIFF audio
'.aifc' => 'audio/x-aiff', // AIFF audio
'.ra' => 'audio/x-pn-realaudio', // RealAudio
'.ram' => 'audio/x-pn-realaudio', // RealAudio
'.rpm' => 'audio/x-pn-realaudio-plugin', // RealAudio (plug-in)
'.wav' => 'audio/x-wav', // Windows WAVE audio
'.mp3' => 'audio/x-mp3', // MP3 files
 
'.gif' => 'image/gif', // gif image
'.ief' => 'image/ief', // Image Exchange Format
'.jpg' => 'image/jpeg', // JPEG image
'.jpe' => 'image/jpeg', // JPEG image
'.jpeg' => 'image/jpeg', // JPEG image
'.pict' => 'image/pict', // Macintosh PICT
'.png' => 'image/png', // PNG image
'.svg' => 'image/svg+xml', // Scalable vector graphics
'.tiff' => 'image/tiff', // TIFF image
'.tif' => 'image/tiff', // TIFF image
'.ras' => 'image/x-cmu-raster', // CMU raster
'.pnm' => 'image/x-portable-anymap', // PBM Anymap format
'.pbm' => 'image/x-portable-bitmap', // PBM Bitmap format
'.pgm' => 'image/x-portable-graymap', // PBM Graymap format
'.ppm' => 'image/x-portable-pixmap', // PBM Pixmap format
'.rgb' => 'image/x-rgb', // RGB Image
'.xbm' => 'image/x-xbitmap', // X Bitmap
'.xpm' => 'image/x-xpixmap', // X Pixmap
'.xwd' => 'image/x-xwindowdump', // X Windows dump (xwd) format
 
'.mpeg' => 'video/mpeg', // MPEG video
'.mpg' => 'video/mpeg', // MPEG video
'.mpe' => 'video/mpeg', // MPEG video
'.mpeg' => 'video/mpeg', // MPEG video
'.qt' => 'video/quicktime', // QuickTime Video
'.mov' => 'video/quicktime', // QuickTime Video
'.avi' => 'video/msvideo', // Microsoft Windows Video
'.movie' => 'video/x-sgi-movie', // SGI Movieplayer format
'.wrl' => 'x-world/x-vrml', // VRML Worlds
 
'.ods' => 'application/vnd.oasis.opendocument.spreadsheet', // OpenDocument Spreadsheet
'.ots' => 'application/vnd.oasis.opendocument.spreadsheet-template', // OpenDocument Spreadsheet Template
'.odp' => 'application/vnd.oasis.opendocument.presentation', // OpenDocument Presentation
'.otp' => 'application/vnd.oasis.opendocument.presentation-template', // OpenDocument Presentation Template
'.odg' => 'application/vnd.oasis.opendocument.graphics', // OpenDocument Drawing
'.otg' => 'application/vnd.oasis.opendocument.graphics-template', // OpenDocument Drawing Template
'.odc' => 'application/vnd.oasis.opendocument.chart', // OpenDocument Chart
'.otc' => 'application/vnd.oasis.opendocument.chart-template', // OpenDocument Chart Template
'.odf' => 'application/vnd.oasis.opendocument.formula', // OpenDocument Formula
'.otf' => 'application/vnd.oasis.opendocument.formula-template', // OpenDocument Formula Template
'.odi' => 'application/vnd.oasis.opendocument.image', // OpenDocument Image
'.oti' => 'application/vnd.oasis.opendocument.image-template', // OpenDocument Image Template
'.odb' => 'application/vnd.oasis.opendocument.database', // OpenDocument Database
'.odt' => 'application/vnd.oasis.opendocument.text', // OpenDocument Text
'.ott' => 'application/vnd.oasis.opendocument.text-template', // OpenDocument Text Template
'.odm' => 'application/vnd.oasis.opendocument.text-master', // OpenDocument Master Document
'.oth' => 'application/vnd.oasis.opendocument.text-web', // OpenDocument HTML Template
);
 
// }}}
 
// {{{ Enscript file extensions
 
// List of extensions recognised by enscript.
 
$extEnscript = array(
'.ada' => 'ada',
'.adb' => 'ada',
'.ads' => 'ada',
'.awk' => 'awk',
'.c' => 'c',
'.c++' => 'cpp',
'.cc' => 'cpp',
'.cmake' => 'cmake',
'CMakeLists.txt' => 'cmake',
'.cpp' => 'cpp',
'.csh' => 'csh',
'.cxx' => 'cpp',
'.diff' => 'diffu',
'.dpr' => 'delphi',
'.e' => 'eiffel',
'.el' => 'elisp',
'.eps' => 'postscript',
'.f' => 'fortran',
'.for' => 'fortran',
'.gs' => 'haskell',
'.h' => 'c',
'.hpp' => 'cpp',
'.hs' => 'haskell',
'.htm' => 'html',
'.html' => 'html',
'.idl' => 'idl',
'.java' => 'java',
'.js' => 'javascript',
'.json' => 'javascript',
'.lgs' => 'haskell',
'.lhs' => 'haskell',
'.m' => 'objc',
'.m4' => 'm4',
'.man' => 'nroff',
'.nr' => 'nroff',
'.p' => 'pascal',
'.pas' => 'delphi',
'.patch' => 'diffu',
'.pkg' => 'sql',
'.pl' => 'perl',
'.pm' => 'perl',
'.pp' => 'pascal',
'.ps' => 'postscript',
'.s' => 'asm',
'.scheme' => 'scheme',
'.scm' => 'scheme',
'.scr' => 'synopsys',
'.sh' => 'sh',
'.shtml' => 'html',
'.sql' => 'sql',
'.st' => 'states',
'.syn' => 'synopsys',
'.synth' => 'synopsys',
'.tcl' => 'tcl',
'.tex' => 'tex',
'.texi' => 'tex',
'.texinfo' => 'tex',
'.v' => 'verilog',
'.vba' => 'vba',
'.vh' => 'verilog',
'.vhd' => 'vhdl',
'.vhdl' => 'vhdl',
'.py' => 'python',
);
 
// }}}
 
// {{{ GeSHi file extensions
 
// List of extensions recognised by GeSHi.
 
$extGeshi = array(
'actionscript3' => array('as'),
'ada' => array('ada', 'adb', 'ads'),
'asm' => array('ash', 'asi', 'asm'),
'asp' => array('asp'),
'bash' => array('sh'),
'bibtex' => array('bib'),
'c' => array('c'),
'cfm' => array('cfm', 'cfml'),
'cmake' => array('cmake', 'CMakeLists.txt'),
'cobol' => array('cbl'),
'cpp' => array('cc', 'cpp', 'cxx', 'c++', 'h', 'hpp'),
'csharp' => array('cs'),
'css' => array('css'),
'd' => array('d'),
'delphi' => array('dpk', 'dpr', 'pas'),
'diff' => array('diff', 'patch'),
'dos' => array('bat', 'cmd'),
'eiffel' => array('e'),
'erlang' => array('erl'),
'email' => array('eml'),
'fortran' => array('f', 'for', 'f90'),
'gettext' => array('po', 'pot'),
'gml' => array('gml'),
'gnuplot' => array('plt'),
'groovy' => array('groovy'),
'haskell' => array('gs', 'hs', 'lgs', 'lhs'),
'html4strict' => array('html', 'htm'),
'idl' => array('idl'),
'ini' => array('desktop', 'ini'),
'java5' => array('java'),
'javascript' => array('js', 'json'),
'latex' => array('tex'),
'lisp' => array('lisp'),
'lua' => array('lua'),
'make' => array('make'),
'matlab' => array('m'),
'perl' => array('pl', 'pm'),
'php' => array('php', 'php3', 'php4', 'php5', 'phps', 'phtml'),
'povray' => array('pov'),
'properties' => array('properties'),
'providex' => array('pvc', 'pvx'),
'python' => array('py'),
'reg' => array('reg'),
'ruby' => array('rb'),
'scala' => array('scala'),
'scheme' => array('scm', 'scheme'),
'scilab' => array('sci'),
'smalltalk' => array('st'),
'sql' => array('sql'),
'tcl' => array('tcl'),
'vb' => array('bas'),
'vbnet' => array('vb'),
'vh' => array('v', 'verilog'),
'vhdl' => array('vhd', 'vhdl'),
'vim' => array('vim'),
'whitespace' => array('ws'),
'xml' => array('xml', 'xsl', 'xsd', 'xib', 'wsdl', 'svg', 'plist', 'jmx'),
'z80' => array('z80'),
);
 
// }}}
 
// Loads English localized strings by default (must go before config.php)
require 'languages/english.php';
 
// Support one WebSVN installation hosting multiple different SVNParentPaths, distinguished by their
// location. Per location, the web server needs to set some environment variable providing the path
// to the config to either exclusively or additionally include, implementing a simple layered config
// this way. That allows, e.g., changing paths to repos per location only and share everything else.
//
// The following implementation deals with multiple most likely problems in such an environment, like
// HTTP redirects influencing the name of the environment variable set and "preg_grep" indexing its
// results depending on the input, so optionally changing between requests.
//
// https://stackoverflow.com/q/3050444/696632
// https://bz.apache.org/bugzilla/show_bug.cgi?id=58739
$confSuccess = 0;
$envPathConf = preg_grep('/^(?:REDIRECT_)*WEBSVN_PATH_CONF$/', array_keys($_SERVER));
$envPathConf = array_values($envPathConf);
$envPathConf = array_key_exists(0, $envPathConf)
? $_SERVER[$envPathConf[0]]
: '';
 
// Get the user's personalised config (requires the locwebsvnhttp stuff above).
if (file_exists('include/config.php')) {
require_once 'include/config.php';
$confSuccess = 1;
}
if (!empty($envPathConf)) {
require_once $envPathConf;
$confSuccess = 1;
}
if (!$confSuccess) {
die('No config applied, either create "include/config.php" or use environment variable ' .
'"WEBSVN_PATH_CONF". The example file "include/distconfig.php" should be copied and ' .
'modified as needed.');
}
 
// Make sure that the input locale is set up correctly
putenv("LANG=".setlocale(LC_ALL, $config->getLocale()));
 
$vars['showageinsteadofdate'] = $config->showAgeInsteadOfDate();
 
// Initialize the version of SVN that is being used by WebSVN internally.
require_once 'include/svnlook.php';
$vars['svnversion'] = $config->getSubversionVersion();
 
// Initialize an array with all query parameters except language and template.
$queryParams = $_GET + $_POST;
unset($queryParams['language']);
unset($queryParams['template']);
$hidden = '';
foreach ($queryParams as $key => $value) {
if (is_array($value)) {
for ($i = 0; $i < count($value); $i++) {
$hidden .= '<input type="hidden" name="'.escape($key).'[]" value="'.escape($value[$i]).'"/>';
}
} else {
$hidden .= '<input type="hidden" name="'.escape($key).'" value="'.escape($value).'"/>';
}
}
 
// If the request specifies a language, store in a cookie. Otherwise, check for cookies specifying a
// particular language already.
$language = ''; // RFC 4646 language tag for representing the selected language.
if (!empty($_REQUEST['language'])) {
$language = $_REQUEST['language'];
setcookie('storedlang', $language, time() + (60 * 60 * 24 * 356 * 10));
setcookie('storedsesslang', $language);
} else if (isset($_COOKIE['storedlang'])) {
$language = $_COOKIE['storedlang'];
} else if (isset($_COOKIE['storedsesslang'])) {
$language = $_COOKIE['storedsesslang'];
}
 
// Load available languages (populates $languages array)
require 'languages/languages.php';
// Get the default language as defined by config.php
$defaultLanguage = $config->getDefaultLanguage();
if (!isset($languages[$defaultLanguage]))
$defaultLanguage = 'en';
// Determine which language to actually use
$language = getUserLanguage($languages, $defaultLanguage, $language);
$vars['language_code'] = $language;
// For languages other than English, load translated strings over existing ones.
if ($language != 'en')
require 'languages/'.$languages[$language][0].'.php';
// Generate the HTML form for selecting a different language
$vars['language_form'] = '<form method="get" action="" id="language">'.$hidden;
$vars['language_select'] = '<select name="language" onchange="javascript:this.form.submit();">';
foreach ($languages as $code => $names) {
$sel = ($code == $language) ? '" selected="selected' : '';
$vars['language_select'] .= '<option value="'.$code.$sel.'">'.$names[2].' &ndash; '.$names[1].'</option>';
}
$vars['language_select'] .= '</select>';
$vars['language_submit'] = '<noscript><input type="submit" value="'.$lang['GO'].'" /></noscript>';
$vars['language_endform'] = '</form>';
 
// Load repository if possible
if ($config->multiViews) {
$rep = null; // MultiViews has custom code to load a repository
} else {
// Load repository matching 'repname' parameter (if set) or the default.
$repname = @$_REQUEST['repname'];
if (isset($repname)) {
$rep = $config->findRepository($repname);
} else {
$reps = $config->getRepositories();
$rep = (isset($reps[0]) ? $reps[0] : null);
}
// Make sure that the user has set up a repository
if ($rep == null) {
$vars['error'] = $lang['SUPPLYREP'];
} else if (is_string($rep)) {
$vars['error'] = $rep;
$rep = null;
} else {
$vars['repurl'] = $config->getURL($rep, '', 'dir');
$vars['clientrooturl'] = $rep->clientRootURL;
$vars['repname'] = escape($rep->getDisplayName());
$vars['allowdownload'] = $rep->getAllowDownload();
}
}
 
// If the request specifies a template, store in a cookie. Otherwise, check for cookies specifying a
// particular template already.
$template = '';
if (!empty($_REQUEST['template'])) {
$template = $_REQUEST['template'];
setcookie('storedtemplate', $template, time() + (60 * 60 * 24 * 365 * 10));
setcookie('storedsesstemplate', $template);
} else if (isset($_COOKIE['storedtemplate'])) {
$template = $_COOKIE['storedtemplate'];
} else if (isset($_COOKIE['storedsesstemplate'])) {
$template = $_COOKIE['storedsesstemplate'];
}
 
$templates = array();
// Skip creating template list when selected repository has specific template.
if ($rep == null || $rep->templatePath === false) {
// Get all templates defined in config.php; use last path component as name.
foreach ($config->templatePaths as $path) {
$templates[$path] = basename($path);
}
$selectedTemplatePath = $config->getTemplatePath();
if ($template != '' && in_array($template, $templates)) {
$selectedTemplatePath = array_search($template, $templates);
$config->userTemplate = $selectedTemplatePath;
}
}
 
// Generate the HTML form for selecting a different template
if (count($templates) > 1) {
$vars['template_form'] = '<form method="get" action="" id="template">'.$hidden;
$vars['template_select'] = '<select name="template" onchange="javascript:this.form.submit();">';
natcasesort($templates);
foreach ($templates as $path => $name) {
$sel = ($path == $selectedTemplatePath) ? ' selected="selected"' : '';
$vars['template_select'] .= '<option value="'.$name.'"'.$sel.'>'.$name.'</option>';
}
$vars['template_select'] .= '</select>';
$vars['template_submit'] = '<noscript><input type="submit" value="'.$lang['GO'].'" /></noscript>';
$vars['template_endform'] = '</form>';
} else {
$vars['template_form'] = '';
$vars['template_select'] = '';
$vars['template_submit'] = '';
$vars['template_endform'] = '';
}
 
$vars['indexurl'] = $config->getURL('', '', 'index');
$vars['validationurl'] = getFullURL($_SERVER['SCRIPT_NAME']).'?'.buildQuery($queryParams + array('template' => $template, 'language' => $language), '%26');
 
$path = !empty($_REQUEST['path']) ? $_REQUEST['path'] : null;
if ($path === null || $path === '')
$path = '/';
$vars['path'] = str_replace('%2F', '/', rawurlencode($path));
$vars['safepath'] = escape($path);
// Set operative and peg revisions (if specified) and save passed-in revision
$rev = (int)@$_REQUEST['rev'];
$peg = (int)@$_REQUEST['peg'];
$search = (string)@$_REQUEST['search'];
if ($peg === 0)
$peg = '';
$passrev = $rev;
 
if (!$config->multiViews) {
// With MultiViews, browse creates the form once the current project is found.
createProjectSelectionForm();
createRevisionSelectionForm();
createSearchSelectionForm();
}
 
// set flag if robots should be blocked
$vars['blockrobots'] = $config->areRobotsBlocked();
 
$listing = array();
 
// Set up response headers
header('Content-Type: text/html; charset=UTF-8');
header('Content-Language: '.$language);
 
// Function to create the project selection HTML form
function createProjectSelectionForm() {
global $config, $vars, $rep, $lang;
 
$vars['projects_form'] = '';
$vars['projects_select'] = '';
$vars['projects_submit'] = '';
$vars['projects_endform'] = '';
 
if (!$config->showRepositorySelectionForm() || count($config->getRepositories()) < 2)
return;
 
if ($rep) {
$currentRepoName = $rep->getDisplayName();
$options = '';
} else {
$currentRepoName = '';
$options = '<option value="" selected="selected"></option>';
}
foreach ($config->getRepositories() as $repository) {
if ($repository->hasReadAccess('/')) {
$repoName = $repository->getDisplayName();
$sel = ($repoName == $currentRepoName) ? ' selected="selected"' : '';
$options .= '<option value="'.escape($repoName).'"'.$sel.'>'.escape($repoName).'</option>';
}
}
if (strlen($options) === 0)
return;
 
$vars['projects_form'] = '<form method="get" action="" id="project">';
if ($config->multiViews)
$vars['projects_form'] .= '<input type="hidden" name="op" value="rep" />';
$vars['projects_select'] = '<select name="repname" onchange="javascript:this.form.submit();">'.$options.'</select>';
$vars['projects_submit'] = '<noscript><input type="submit" value="'.$lang['GO'].'" /></noscript>';
$vars['projects_endform'] = '</form>';
}
 
// Function to create the revision selection HTML form
function createRevisionSelectionForm() {
global $config, $lang, $vars, $rep, $path, $rev, $peg;
 
if ($rep == null)
return;
 
$params = array();
if (!$config->multiViews) {
$params['repname'] = $rep->getDisplayName();
if ($path === null)
$path = !empty($_REQUEST['path']) ? $_REQUEST['path'] : null;
if ($path && $path != '/')
$params['path'] = $path;
}
if ($peg || $rev)
$params['peg'] = ($peg ? $peg : $rev);
$hidden = '';
foreach ($params as $key => $value) {
$hidden .= '<input type="hidden" name="'.$key.'" value="'.escape($value).'" />';
}
// The blank "action" attribute makes form link back to the containing page.
$vars['revision_form'] = '<form method="get" action="" id="revision">'.$hidden;
if ($rev === null)
$rev = (int)@$_REQUEST['rev'];
$vars['revision_input'] = '<input type="text" size="5" name="rev" placeholder="'.($rev ? $rev : 'HEAD').'" />';
$vars['revision_submit'] = '<input type="submit" value="'.$lang['GO'].'" />';
$vars['revision_endform'] = '</form>';
}
 
function createSearchSelectionForm() {
global $config, $lang, $vars, $rep, $path, $rev, $peg, $search;
if ($rep === null)
return;
$params = array();
if (!$config->multiViews) {
$params['repname'] = $rep->getDisplayName();
if ($path === null)
$path = !empty($_REQUEST['path']) ? $_REQUEST['path'] : null;
if ($path && $path != '/')
$params['path'] = $path;
}
if ($peg || $rev)
$params['rev'] = ($peg ? $peg : $rev);
$hidden = '';
foreach ($params as $key => $value) {
$hidden .= '<input type="hidden" name="'.$key.'" value="'.escape($value).'" />';
}
$vars['search'] = true;
$vars['search_form'] = '<form method="get" action="'.$config->getURL($rep, '', 'search').'" id="search">'.$hidden;
$search = $search? $search : $lang['SEARCH_PLACEHOLDER'];
$vars['search_input'] = '<input type="text" size="20" name="search" placeholder="'.$search.'" />';
$vars['search_submit'] = '<input type="submit" value="'.$lang['SEARCH'].'" />';
$vars['search_endform'] = '</form>';
}
function sendHeaderForbidden() {
http_response_code(403);
}
/WebSVN/include/svnlook.php
0,0 → 1,1270
<?php
// WebSVN - Subversion repository viewing via the web using PHP
// Copyright (C) 2004-2006 Tim Armes
//
// 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; either version 2 of the License, or
// (at your option) any later version.
//
// 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; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// --
//
// svn-look.php
//
// Svn bindings
//
// These binding currently use the svn command line to achieve their goal. Once a proper
// SWIG binding has been produced for PHP, there'll be an option to use that instead.
 
require_once 'include/utils.php';
 
// {{{ Classes for retaining log information ---
 
$debugxml = false;
 
class SVNInfoEntry {
var $rev = 1;
var $path = '';
var $isdir = null;
}
 
class SVNMod {
var $action = '';
var $copyfrom = '';
var $copyrev = '';
var $path = '';
var $isdir = null;
}
 
class SVNListEntry {
var $rev = 1;
var $author = '';
var $date = '';
var $committime;
var $age = '';
var $file = '';
var $isdir = null;
}
 
class SVNList {
var $entries; // Array of entries
var $curEntry; // Current entry
 
var $path = ''; // The path of the list
}
 
class SVNLogEntry {
var $rev = 1;
var $author = '';
var $date = '';
var $committime;
var $age = '';
var $msg = '';
var $path = '';
var $precisePath = '';
 
var $mods;
var $curMod;
}
 
function SVNLogEntry_compare($a, $b) {
return strnatcasecmp($a->path, $b->path);
}
 
class SVNLog {
var $entries; // Array of entries
var $curEntry; // Current entry
 
var $path = ''; // Temporary variable used to trace path history
 
// findEntry
//
// Return the entry for a given revision
 
function findEntry($rev) {
foreach ($this->entries as $index => $entry) {
if ($entry->rev == $rev) {
return $index;
}
}
}
}
 
// }}}
 
// {{{ XML parsing functions---
 
$curTag = '';
 
$curInfo = 0;
 
// {{{ infoStartElement
 
function infoStartElement($parser, $name, $attrs) {
global $curInfo, $curTag, $debugxml;
 
switch ($name) {
case 'INFO':
if ($debugxml) print 'Starting info'."\n";
break;
 
case 'ENTRY':
if ($debugxml) print 'Creating info entry'."\n";
 
if (count($attrs)) {
foreach ($attrs as $k => $v) {
switch ($k) {
case 'KIND':
if ($debugxml) print 'Kind '.$v."\n";
$curInfo->isdir = ($v == 'dir');
break;
case 'REVISION':
if ($debugxml) print 'Revision '.$v."\n";
$curInfo->rev = $v;
break;
}
}
}
break;
 
default:
$curTag = $name;
break;
}
}
 
// }}}
 
// {{{ infoEndElement
 
function infoEndElement($parser, $name) {
global $curInfo, $debugxml, $curTag;
 
switch ($name) {
case 'ENTRY':
if ($debugxml) print 'Ending info entry'."\n";
if ($curInfo->isdir) {
$curInfo->path .= '/';
}
break;
}
 
$curTag = '';
}
 
// }}}
 
// {{{ infoCharacterData
 
function infoCharacterData($parser, $data) {
global $curInfo, $curTag, $debugxml;
 
switch ($curTag) {
case 'URL':
if ($debugxml) print 'URL: '.$data."\n";
$curInfo->path = $data;
break;
 
case 'ROOT':
if ($debugxml) print 'Root: '.$data."\n";
$curInfo->path = urldecode(substr($curInfo->path, strlen($data)));
break;
}
}
 
// }}}
 
$curList = 0;
 
// {{{ listStartElement
 
function listStartElement($parser, $name, $attrs) {
global $curList, $curTag, $debugxml;
 
switch ($name) {
case 'LIST':
if ($debugxml) print 'Starting list'."\n";
 
if (count($attrs)) {
foreach ($attrs as $k => $v) {
switch ($k) {
case 'PATH':
if ($debugxml) print 'Path '.$v."\n";
$curList->path = $v;
break;
}
}
}
break;
 
case 'ENTRY':
if ($debugxml) print 'Creating new entry'."\n";
$curList->curEntry = new SVNListEntry;
 
if (count($attrs)) {
foreach ($attrs as $k => $v) {
switch ($k) {
case 'KIND':
if ($debugxml) print 'Kind '.$v."\n";
$curList->curEntry->isdir = ($v == 'dir');
break;
}
}
}
break;
 
case 'COMMIT':
if ($debugxml) print 'Commit'."\n";
 
if (count($attrs)) {
foreach ($attrs as $k => $v) {
switch ($k) {
case 'REVISION':
if ($debugxml) print 'Revision '.$v."\n";
$curList->curEntry->rev = $v;
break;
}
}
}
break;
 
default:
$curTag = $name;
break;
}
}
 
// }}}
 
// {{{ listEndElement
 
function listEndElement($parser, $name) {
global $curList, $debugxml, $curTag;
 
switch ($name) {
case 'ENTRY':
if ($debugxml) print 'Ending new list entry'."\n";
if ($curList->curEntry->isdir) {
$curList->curEntry->file .= '/';
}
$curList->entries[] = $curList->curEntry;
$curList->curEntry = null;
break;
}
 
$curTag = '';
}
 
// }}}
 
// {{{ listCharacterData
 
function listCharacterData($parser, $data) {
global $curList, $curTag, $debugxml;
 
switch ($curTag) {
case 'NAME':
if ($debugxml) print 'Name: '.$data."\n";
if ($data === false || $data === '') return;
$curList->curEntry->file .= $data;
break;
 
case 'AUTHOR':
if ($debugxml) print 'Author: '.$data."\n";
if ($data === false || $data === '') return;
if (function_exists('mb_detect_encoding') && function_exists('mb_convert_encoding'))
$data = mb_convert_encoding($data, 'UTF-8', mb_detect_encoding($data));
$curList->curEntry->author .= $data;
break;
 
case 'DATE':
if ($debugxml) print 'Date: '.$data."\n";
if ($data === false || $data === '') return;
$committime = parseSvnTimestamp($data);
$curList->curEntry->committime = $committime;
$curList->curEntry->date = date('Y-m-d H:i:s', $committime);
$curList->curEntry->age = datetimeFormatDuration(max(time() - $committime, 0), true, true);
break;
}
}
 
// }}}
 
$curLog = 0;
 
// {{{ logStartElement
 
function logStartElement($parser, $name, $attrs) {
global $curLog, $curTag, $debugxml;
 
switch ($name) {
case 'LOGENTRY':
if ($debugxml) print 'Creating new log entry'."\n";
$curLog->curEntry = new SVNLogEntry;
$curLog->curEntry->mods = array();
 
$curLog->curEntry->path = $curLog->path;
 
if (count($attrs)) {
foreach ($attrs as $k => $v) {
switch ($k) {
case 'REVISION':
if ($debugxml) print 'Revision '.$v."\n";
$curLog->curEntry->rev = $v;
break;
}
}
}
break;
 
case 'PATH':
if ($debugxml) print 'Creating new path'."\n";
$curLog->curEntry->curMod = new SVNMod;
 
if (count($attrs)) {
foreach ($attrs as $k => $v) {
switch ($k) {
case 'ACTION':
if ($debugxml) print 'Action '.$v."\n";
$curLog->curEntry->curMod->action = $v;
break;
 
case 'COPYFROM-PATH':
if ($debugxml) print 'Copy from: '.$v."\n";
$curLog->curEntry->curMod->copyfrom = $v;
break;
 
case 'COPYFROM-REV':
$curLog->curEntry->curMod->copyrev = $v;
break;
 
case 'KIND':
if ($debugxml) print 'Kind '.$v."\n";
$curLog->curEntry->curMod->isdir = ($v == 'dir');
break;
}
}
}
 
$curTag = $name;
break;
 
default:
$curTag = $name;
break;
}
}
 
// }}}
 
// {{{ logEndElement
 
function logEndElement($parser, $name) {
global $curLog, $debugxml, $curTag;
 
switch ($name) {
case 'LOGENTRY':
if ($debugxml) print 'Ending new log entry'."\n";
$curLog->entries[] = $curLog->curEntry;
break;
 
case 'PATH':
// The XML returned when a file is renamed/branched in inconsistent.
// In the case of a branch, the path doesn't include the leafname.
// In the case of a rename, it does. Ludicrous.
 
if (!empty($curLog->path)) {
$pos = strrpos($curLog->path, '/');
$curpath = substr($curLog->path, 0, $pos);
$leafname = substr($curLog->path, $pos + 1);
} else {
$curpath = '';
$leafname = '';
}
 
$curMod = $curLog->curEntry->curMod;
if ($curMod->action == 'A') {
if ($debugxml) print 'Examining added path "'.$curMod->copyfrom.'" - Current path = "'.$curpath.'", leafname = "'.$leafname.'"'."\n";
if ($curMod->path == $curLog->path) {
// For directories and renames
$curLog->path = $curMod->copyfrom;
} else if ($curMod->path == $curpath || $curMod->path == $curpath.'/') {
// Logs of files that have moved due to branching
$curLog->path = $curMod->copyfrom.'/'.$leafname;
} else {
$curLog->path = str_replace($curMod->path, $curMod->copyfrom, $curLog->path);
}
if ($debugxml) print 'New path for comparison: "'.$curLog->path.'"'."\n";
}
 
if ($debugxml) print 'Ending path'."\n";
$curLog->curEntry->mods[] = $curLog->curEntry->curMod;
break;
 
case 'MSG':
$curLog->curEntry->msg = trim($curLog->curEntry->msg);
if ($debugxml) print 'Completed msg = "'.$curLog->curEntry->msg.'"'."\n";
break;
}
 
$curTag = '';
}
 
// }}}
 
// {{{ logCharacterData
 
function logCharacterData($parser, $data) {
global $curLog, $curTag, $debugxml;
 
switch ($curTag) {
case 'AUTHOR':
if ($debugxml) print 'Author: '.$data."\n";
if ($data === false || $data === '') return;
if (function_exists('mb_detect_encoding') && function_exists('mb_convert_encoding'))
$data = mb_convert_encoding($data, 'UTF-8', mb_detect_encoding($data));
$curLog->curEntry->author .= $data;
break;
 
case 'DATE':
if ($debugxml) print 'Date: '.$data."\n";
if ($data === false || $data === '') return;
$committime = parseSvnTimestamp($data);
$curLog->curEntry->committime = $committime;
$curLog->curEntry->date = date('Y-m-d H:i:s', $committime);
$curLog->curEntry->age = datetimeFormatDuration(max(time() - $committime, 0), true, true);
break;
 
case 'MSG':
if ($debugxml) print 'Msg: '.$data."\n";
if (function_exists('mb_detect_encoding') && function_exists('mb_convert_encoding'))
$data = mb_convert_encoding($data, 'UTF-8', mb_detect_encoding($data));
$curLog->curEntry->msg .= $data;
break;
 
case 'PATH':
if ($debugxml) print 'Path name: '.$data."\n";
if ($data === false || $data === '') return;
$curLog->curEntry->curMod->path .= $data;
break;
}
}
 
// }}}
 
// }}}
 
// {{{ internal functions (_topLevel and _listSort)
 
// Function returns true if the give entry in a directory tree is at the top level
 
function _topLevel($entry) {
// To be at top level, there must be one space before the entry
return (strlen($entry) > 1 && $entry[0] == ' ' && $entry[ 1 ] != ' ');
}
 
// Function to sort two given directory entries.
// Directories go at the top if config option alphabetic is not set
 
function _listSort($e1, $e2) {
global $config;
 
$file1 = $e1->file;
$file2 = $e2->file;
$isDir1 = ($file1[strlen($file1) - 1] == '/');
$isDir2 = ($file2[strlen($file2) - 1] == '/');
 
if (!$config->isAlphabeticOrder()) {
if ($isDir1 && !$isDir2) return -1;
if ($isDir2 && !$isDir1) return 1;
}
 
if ($isDir1) $file1 = substr($file1, 0, -1);
if ($isDir2) $file2 = substr($file2, 0, -1);
 
return strnatcasecmp($file1, $file2);
}
 
// }}}
 
// {{{ encodePath
 
// Function to encode a URL without encoding the /'s
 
function encodePath($uri) {
global $config;
 
$uri = str_replace(DIRECTORY_SEPARATOR, '/', $uri);
if (function_exists('mb_detect_encoding') && function_exists('mb_convert_encoding')) {
$uri = mb_convert_encoding($uri, 'UTF-8', mb_detect_encoding($uri));
}
 
$parts = explode('/', $uri);
$partscount = count($parts);
for ($i = 0; $i < $partscount; $i++) {
// do not rawurlencode the 'svn+ssh://' part!
if ($i != 0 || $parts[$i] != 'svn+ssh:') {
$parts[$i] = rawurlencode($parts[$i]);
}
}
 
$uri = implode('/', $parts);
 
// Quick hack. Subversion seems to have a bug surrounding the use of %3A instead of :
 
$uri = str_replace('%3A', ':', $uri);
 
// Correct for Window share names
if ($config->serverIsWindows) {
if (substr($uri, 0, 2) == '//') {
$uri = '\\'.substr($uri, 2, strlen($uri));
}
 
if (substr($uri, 0, 10) == 'file://///' ) {
$uri = 'file:///\\'.substr($uri, 10, strlen($uri));
}
}
 
return $uri;
}
 
// }}}
 
function _equalPart($str1, $str2) {
$len1 = strlen($str1);
$len2 = strlen($str2);
$i = 0;
while ($i < $len1 && $i < $len2) {
if (strcmp($str1[$i], $str2[$i]) != 0) {
break;
}
$i++;
}
if ($i == 0) {
return '';
}
return substr($str1, 0, $i);
}
 
function _logError($string) {
$string = preg_replace("/--password '.*'/", "--password '[...]'", $string);
error_log($string);
}
 
// The SVNRepository class
 
class SVNRepository {
var $repConfig;
var $geshi = null;
 
function __construct($repConfig) {
$this->repConfig = $repConfig;
}
 
// {{{ highlightLine
//
// Distill line-spanning syntax highlighting so that each line can stand alone
// (when invoking on the first line, $attributes should be an empty array)
// Invoked to make sure all open syntax highlighting tags (<font>, <i>, <b>, etc.)
// are closed at the end of each line and re-opened on the next line
 
function highlightLine($line, &$attributes) {
$hline = '';
 
// Apply any highlighting in effect from the previous line
foreach ($attributes as $attr) {
$hline .= $attr['text'];
}
 
// append the new line
$hline .= $line;
 
// update attributes
for ($line = strstr($line, '<'); $line; $line = strstr(substr($line, 1), '<')) {
if (substr($line, 1, 1) == '/') {
// if this closes a tag, remove most recent corresponding opener
$tagNamLen = strcspn($line, '> '."\t", 2);
$tagNam = substr($line, 2, $tagNamLen);
foreach (array_reverse(array_keys($attributes)) as $k) {
if ($attributes[$k]['tag'] == $tagNam) {
unset($attributes[$k]);
break;
}
}
} else {
// if this opens a tag, add it to the list
$tagNamLen = strcspn($line, '> '."\t", 1);
$tagNam = substr($line, 1, $tagNamLen);
$tagLen = strcspn($line, '>') + 1;
$attributes[] = array('tag' => $tagNam, 'text' => substr($line, 0, $tagLen));
}
}
 
// close any still-open tags
foreach (array_reverse($attributes) as $attr) {
$hline .= '</'.$attr['tag'].'>';
}
 
// XXX: this just simply replaces [ and ] with their entities to prevent
// it from being parsed by the template parser; maybe something more
// elegant is in order?
$hline = str_replace('[', '&#91;', str_replace(']', '&#93;', $hline) );
return $hline;
}
 
// }}}
 
// Private function to simplify creation of common SVN command string text.
function svnCommandString($command, $path, $rev, $peg) {
global $config;
return $config->getSvnCommand().$this->repConfig->svnCredentials().' '.$command.' '.($rev ? '-r '.$rev.' ' : '').quote(encodePath($this->getSvnPath($path)).'@'.($peg ? $peg : ''));
}
 
// Private function to simplify creation of enscript command string text.
function enscriptCommandString($path) {
global $config, $extEnscript;
 
$filename = basename($path);
$ext = strrchr($path, '.');
 
$lang = false;
if (array_key_exists($filename, $extEnscript)) {
$lang = $extEnscript[$filename];
} else if ($ext && array_key_exists(strtolower($ext), $extEnscript)) {
$lang = $extEnscript[strtolower($ext)];
}
 
$cmd = $config->enscript.' --language=html';
if ($lang !== false) {
$cmd .= ' --color --'.(!$config->getUseEnscriptBefore_1_6_3() ? 'highlight' : 'pretty-print').'='.$lang;
}
$cmd .= ' -o -';
return $cmd;
}
 
// {{{ getFileContents
//
// Dump the content of a file to the given filename
 
function getFileContents($path, $filename, $rev = 0, $peg = '', $pipe = '', $highlight = 'file') {
global $config;
assert ($highlight == 'file' || $highlight == 'no' || $highlight == 'line');
 
$highlighted = false;
 
// If there's no filename, just deliver the contents as-is to the user
if ($filename == '') {
$cmd = $this->svnCommandString('cat', $path, $rev, $peg);
passthruCommand($cmd.' '.$pipe);
return $highlighted;
}
 
// Get the file contents info
 
$tempname = $filename;
if ($highlight == 'line') {
$tempname = tempnamWithCheck($config->getTempDir(), '');
}
$highlighted = true;
$shouldTrimOutput = false;
$explodeStr = "\n";
if ($highlight != 'no' && $config->useGeshi && $geshiLang = $this->highlightLanguageUsingGeshi($path)) {
$this->applyGeshi($path, $tempname, $geshiLang, $rev, $peg, false, $highlight);
// Geshi outputs in HTML format, enscript does not
$shouldTrimOutput = true;
$explodeStr = "<br />";
} else if ($highlight != 'no' && $config->useEnscript) {
// Get the files, feed it through enscript, then remove the enscript headers using sed
// Note that the sed command returns only the part of the file between <PRE> and </PRE>.
// It's complicated because it's designed not to return those lines themselves.
$cmd = $this->svnCommandString('cat', $path, $rev, $peg);
$cmd = $cmd.' | '.$this->enscriptCommandString($path).' | '.
$config->sed.' -n '.$config->quote.'1,/^<PRE.$/!{/^<\\/PRE.$/,/^<PRE.$/!p;}'.$config->quote.' > '.$tempname;
} else {
$highlighted = false;
$cmd = $this->svnCommandString('cat', $path, $rev, $peg);
$cmd = $cmd.' > '.quote($filename);
}
 
if (isset($cmd)) {
$error = '';
$output = runCommand($cmd, true, $error);
 
if (!empty($error)) {
global $lang;
_logError($lang['BADCMD'].': '.$cmd);
_logError($error);
 
global $vars;
$vars['warning'] = nl2br(escape(toOutputEncoding($error)));
}
}
 
if ($highlighted && $highlight == 'line') {
// If we need each line independently highlighted (e.g. for diff or blame)
// then we'll need to filter the output of the highlighter
// to make sure tags like <font>, <i> or <b> don't span lines
 
$dst = fopen($filename, 'w');
if ($dst) {
$content = file_get_contents($tempname);
$content = explode($explodeStr, $content);
 
// $attributes is used to remember what highlighting attributes
// are in effect from one line to the next
$attributes = array(); // start with no attributes in effect
 
foreach ($content as $line) {
if ($shouldTrimOutput) {
$line = trim($line);
}
fputs($dst, $this->highlightLine($line, $attributes)."\n");
}
fclose($dst);
}
}
if ($tempname != $filename) {
@unlink($tempname);
}
return $highlighted;
}
 
// }}}
 
// {{{ highlightLanguageUsingGeshi
//
// check if geshi can highlight the given extension and return the language
 
function highlightLanguageUsingGeshi($path) {
global $config;
global $extGeshi;
 
$filename = basename($path);
$ext = strrchr($path, '.');
if (substr($ext, 0, 1) == '.') $ext = substr($ext, 1);
 
foreach ($extGeshi as $language => $extensions) {
if (in_array($filename, $extensions) || in_array(strtolower($ext), $extensions)) {
if ($this->geshi === null) {
if (!defined('USE_AUTOLOADER')) {
require_once $config->getGeshiScript();
}
$this->geshi = new GeSHi();
}
$this->geshi->set_language($language);
if ($this->geshi->error() === false) {
return $language;
}
}
}
return '';
}
 
// }}}
 
// {{{ applyGeshi
//
// perform syntax highlighting using geshi
 
function applyGeshi($path, $filename, $language, $rev, $peg = '', $return = false, $highlight = 'file') {
global $config;
 
// Output the file to the filename
$error = '';
$cmd = $this->svnCommandString('cat', $path, $rev, $peg).' > '.quote($filename);
$output = runCommand($cmd, true, $error);
 
if (!empty($error)) {
global $lang;
_logError($lang['BADCMD'].': '.$cmd);
_logError($error);
 
global $vars;
$vars['warning'] = 'Unable to cat file: '.nl2br(escape(toOutputEncoding($error)));
return;
}
 
$source = file_get_contents($filename);
 
if ($this->geshi === null) {
if (!defined('USE_AUTOLOADER')) {
require_once $config->getGeshiScript();
}
$this->geshi = new GeSHi();
}
 
$this->geshi->set_source($source);
$this->geshi->set_language($language);
$this->geshi->set_header_type(GESHI_HEADER_NONE);
$this->geshi->set_overall_class('geshi');
$this->geshi->set_tab_width($this->repConfig->getExpandTabsBy());
 
if ($highlight == 'file') {
$this->geshi->enable_line_numbers(GESHI_FANCY_LINE_NUMBERS);
$this->geshi->set_overall_id('geshi');
$this->geshi->enable_ids(true);
}
 
if ($return) {
return $this->geshi->parse_code();
} else {
$f = @fopen($filename, 'w');
fwrite($f, $this->geshi->parse_code());
fclose($f);
}
}
 
// }}}
 
// {{{ listFileContents
//
// Print the contents of a file without filling up Apache's memory
 
function listFileContents($path, $rev = 0, $peg = '') {
global $config;
 
if ($config->useGeshi && $geshiLang = $this->highlightLanguageUsingGeshi($path)) {
$tempname = tempnamWithCheck($config->getTempDir(), 'websvn');
if ($tempname !== false) {
print toOutputEncoding($this->applyGeshi($path, $tempname, $geshiLang, $rev, $peg, true));
@unlink($tempname);
}
} else {
$pre = false;
$cmd = $this->svnCommandString('cat', $path, $rev, $peg);
if ($config->useEnscript) {
$cmd .= ' | '.$this->enscriptCommandString($path).' | '.
$config->sed.' -n '.$config->quote.'/^<PRE.$/,/^<\\/PRE.$/p'.$config->quote;
} else {
$pre = true;
}
 
if ($result = popenCommand($cmd, 'r')) {
if ($pre)
echo '<pre>';
while (!feof($result)) {
$line = fgets($result, 1024);
$line = toOutputEncoding($line);
if ($pre) {
$line = escape($line);
}
print hardspace($line);
}
if ($pre)
echo '</pre>';
pclose($result);
}
}
}
 
// }}}
 
// {{{ listReadmeContents
//
// Parse the README.md file
function listReadmeContents($path, $rev = 0, $peg = '') {
global $config;
 
$file = "README.md";
 
if ($this->isFile($path.$file) != True)
{
return;
}
 
if (!$config->getUseParsedown())
{
return;
}
 
// Autoloader handles most of the time
if (!defined('USE_AUTOLOADER')) {
require_once $config->getParsedownScript();
}
 
$mdParser = new Parsedown();
$cmd = $this->svnCommandString('cat', $path.$file, $rev, $peg);
 
if (!($result = popenCommand($cmd, 'r')))
{
return;
}
 
echo('<div id="wrap">');
while (!feof($result))
{
$line = fgets($result, 1024);
echo $mdParser->text($line);
}
echo('</div>');
pclose($result);
 
}
 
// }}}
 
// {{{ getBlameDetails
//
// Dump the blame content of a file to the given filename
 
function getBlameDetails($path, $filename, $rev = 0, $peg = '') {
$error = '';
$cmd = $this->svnCommandString('blame', $path, $rev, $peg).' > '.quote($filename);
$output = runCommand($cmd, true, $error);
 
if (!empty($error)) {
global $lang;
_logError($lang['BADCMD'].': '.$cmd);
_logError($error);
 
global $vars;
$vars['warning'] = 'No blame info: '.nl2br(escape(toOutputEncoding($error)));
}
}
 
// }}}
 
function getProperties($path, $rev = 0, $peg = '') {
$cmd = $this->svnCommandString('proplist', $path, $rev, $peg);
$ret = runCommand($cmd, true);
$properties = array();
if (is_array($ret)) {
foreach ($ret as $line) {
if (substr($line, 0, 1) == ' ') {
$properties[] = ltrim($line);
}
}
}
return $properties;
}
 
// {{{ getProperty
 
function getProperty($path, $property, $rev = 0, $peg = '') {
$cmd = $this->svnCommandString('propget '.$property, $path, $rev, $peg);
$ret = runCommand($cmd, true);
// Remove the surplus newline
if (count($ret)) {
unset($ret[count($ret) - 1]);
}
return implode("\n", $ret);
}
 
// }}}
 
// {{{ exportDirectory
//
// Exports the directory to the given location
 
function exportRepositoryPath($path, $filename, $rev = 0, $peg = '') {
$cmd = $this->svnCommandString('export', $path, $rev, $peg).' '.quote($filename.'@');
$retcode = 0;
execCommand($cmd, $retcode);
if ($retcode != 0) {
global $lang;
_logError($lang['BADCMD'].': '.$cmd);
}
return $retcode;
}
 
// }}}
 
// {{{ _xmlParseCmdOutput
 
function _xmlParseCmdOutput($cmd, $startElem, $endElem, $charData) {
$error = '';
$lines = runCommand($cmd, false, $error);
$linesCnt = count($lines);
$xml_parser = xml_parser_create('UTF-8');
 
xml_parser_set_option($xml_parser, XML_OPTION_CASE_FOLDING, true);
xml_set_element_handler($xml_parser, $startElem, $endElem);
xml_set_character_data_handler($xml_parser, $charData);
 
for ($i = 0; $i < $linesCnt; ++$i) {
$line = $lines[$i] . "\n";
$isLast = $i == ($linesCnt - 1);
 
if (xml_parse($xml_parser, $line, $isLast)) {
continue;
}
 
$errorMsg = sprintf('XML error: %s (%d) at line %d column %d byte %d'."\n".'cmd: %s',
xml_error_string(xml_get_error_code($xml_parser)),
xml_get_error_code($xml_parser),
xml_get_current_line_number($xml_parser),
xml_get_current_column_number($xml_parser),
xml_get_current_byte_index($xml_parser),
$cmd);
 
if (xml_get_error_code($xml_parser) == 5) {
break;
}
 
// errors can contain sensitive info! don't echo this ~J
_logError($errorMsg);
exit;
}
 
xml_parser_free($xml_parser);
if (empty($error)) {
return;
}
 
$error = toOutputEncoding(nl2br(str_replace('svn: ', '', $error)));
global $lang;
_logError($lang['BADCMD'].': '.$cmd);
_logError($error);
 
global $vars;
if (strstr($error, 'found format')) {
$vars['error'] = 'Repository uses a newer format than Subversion '.$config->getSubversionVersion().' can read. ("'.nl2br(escape(toOutputEncoding(substr($error, strrpos($error, 'Expected'))))).'.")';
} else if (strstr($error, 'No such revision')) {
$vars['warning'] = 'Revision '.$rev.' of this resource does not exist.';
} else {
$vars['error'] = $lang['BADCMD'].': <code>'.escape(stripCredentialsFromCommand($cmd)).'</code><br />'.nl2br(escape(toOutputEncoding($error)));
}
}
 
// }}}
 
// {{{ getInfo
 
function getInfo($path, $rev = 0, $peg = '') {
global $config, $curInfo;
 
// Since directories returned by svn log don't have trailing slashes (:-(), we need to remove
// the trailing slash from the path for comparison purposes
 
if ($path[strlen($path) - 1] == '/' && $path != '/') {
$path = substr($path, 0, -1);
}
 
$curInfo = new SVNInfoEntry;
 
// Get the svn info
 
if ($rev == 0) {
$headlog = $this->getLog('/', '', '', true, 1);
if ($headlog && isset($headlog->entries[0]))
$rev = $headlog->entries[0]->rev;
}
 
$cmd = $this->svnCommandString('info --xml', $path, $rev, $peg);
$this->_xmlParseCmdOutput($cmd, 'infoStartElement', 'infoEndElement', 'infoCharacterData');
 
if ($this->repConfig->subpath !== null) {
if (substr($curInfo->path, 0, strlen($this->repConfig->subpath) + 1) === '/'. $this->repConfig->subpath) {
$curInfo->path = substr($curInfo->path, strlen($this->repConfig->subpath) + 1);
} else {
// hide entry when file is outside of subpath
return null;
}
}
 
return $curInfo;
}
 
// }}}
 
// {{{ getList
 
function getList($path, $rev = 0, $peg = '') {
global $config, $curList;
 
// Since directories returned by svn log don't have trailing slashes (:-(), we need to remove
// the trailing slash from the path for comparison purposes
 
if ($path[strlen($path) - 1] == '/' && $path != '/') {
$path = substr($path, 0, -1);
}
 
$curList = new SVNList;
$curList->entries = array();
$curList->path = $path;
 
// Get the list info
 
if ($rev == 0) {
$headlog = $this->getLog('/', '', '', true, 1);
if ($headlog && isset($headlog->entries[0]))
$rev = $headlog->entries[0]->rev;
}
 
if ($config->showLoadAllRepos()) {
$cmd = $this->svnCommandString('list -R --xml', $path, $rev, $peg);
$this->_xmlParseCmdOutput($cmd, 'listStartElement', 'listEndElement', 'listCharacterData');
}
else {
$cmd = $this->svnCommandString('list --xml', $path, $rev, $peg);
$this->_xmlParseCmdOutput($cmd, 'listStartElement', 'listEndElement', 'listCharacterData');
usort($curList->entries, '_listSort');
}
 
return $curList;
}
 
// }}}
 
// {{{ getListSearch
 
function getListSearch($path, $term = '', $rev = 0, $peg = '') {
global $config, $curList;
 
// Since directories returned by "svn log" don't have trailing slashes (:-(), we need to
// remove the trailing slash from the path for comparison purposes.
if (($path[strlen($path) - 1] == '/') && ($path != '/')) {
$path = substr($path, 0, -1);
}
 
$curList = new SVNList;
$curList->entries = array();
$curList->path = $path;
 
// Get the list info
 
if ($rev == 0) {
$headlog = $this->getLog('/', '', '', true, 1);
if ($headlog && isset($headlog->entries[0]))
$rev = $headlog->entries[0]->rev;
}
 
$term = escapeshellarg($term);
$cmd = 'list -R --search ' . $term . ' --xml';
$cmd = $this->svnCommandString($cmd, $path, $rev, $peg);
$this->_xmlParseCmdOutput($cmd, 'listStartElement', 'listEndElement', 'listCharacterData');
 
return $curList;
}
 
// }}}
 
 
// {{{ getLog
 
function getLog($path, $brev = '', $erev = 1, $quiet = false, $limit = 2, $peg = '', $verbose = false) {
global $config, $curLog;
 
// Since directories returned by svn log don't have trailing slashes (:-(),
// we must remove the trailing slash from the path for comparison purposes.
if (!empty($path) && $path != '/' && $path[strlen($path) - 1] == '/') {
$path = substr($path, 0, -1);
}
 
$curLog = new SVNLog;
$curLog->entries = array();
$curLog->path = $path;
 
// Get the log info
$effectiveRev = ($brev && $erev ? $brev.':'.$erev : ($brev ? $brev.':1' : ''));
$effectivePeg = ($peg ? $peg : ($brev ? $brev : ''));
$cmd = $this->svnCommandString('log --xml '.($verbose ? '--verbose' : ($quiet ? '--quiet' : '')).($limit != 0 ? ' --limit '.$limit : ''), $path, $effectiveRev, $effectivePeg);
 
$this->_xmlParseCmdOutput($cmd, 'logStartElement', 'logEndElement', 'logCharacterData');
 
foreach ($curLog->entries as $entryKey => $entry) {
$fullModAccess = true;
$anyModAccess = (count($entry->mods) == 0);
$precisePath = null;
foreach ($entry->mods as $modKey => $mod) {
$access = $this->repConfig->hasLogReadAccess($mod->path);
if ($access) {
$anyModAccess = true;
 
// find path which is parent of all modification but more precise than $curLogEntry->path
$modpath = $mod->path;
if (!$mod->isdir || $mod->action == 'D') {
$pos = strrpos($modpath, '/');
$modpath = substr($modpath, 0, $pos + 1);
}
if (strlen($modpath) == 0 || substr($modpath, -1) !== '/') {
$modpath .= '/';
}
//compare with current precise path
if ($precisePath === null) {
$precisePath = $modpath;
} else {
$equalPart = _equalPart($precisePath, $modpath);
if (substr($equalPart, -1) !== '/') {
$pos = strrpos($equalPart, '/');
$equalPart = substr($equalPart, 0, $pos + 1);
}
$precisePath = $equalPart;
}
 
// fix paths if command was for a subpath repository
if ($this->repConfig->subpath !== null) {
if (substr($mod->path, 0, strlen($this->repConfig->subpath) + 1) === '/'. $this->repConfig->subpath) {
$curLog->entries[$entryKey]->mods[$modKey]->path = substr($mod->path, strlen($this->repConfig->subpath) + 1);
} else {
// hide modified entry when file is outside of subpath
unset($curLog->entries[$entryKey]->mods[$modKey]);
}
}
} else {
// hide modified entry when access is prohibited
unset($curLog->entries[$entryKey]->mods[$modKey]);
$fullModAccess = false;
}
}
if (!$fullModAccess) {
// hide commit message when access to any of the entries is prohibited
$curLog->entries[$entryKey]->msg = '';
}
if (!$anyModAccess) {
// hide author and date when access to all of the entries is prohibited
$curLog->entries[$entryKey]->author = '';
$curLog->entries[$entryKey]->date = '';
$curLog->entries[$entryKey]->committime = '';
$curLog->entries[$entryKey]->age = '';
}
 
if ($precisePath !== null) {
$curLog->entries[$entryKey]->precisePath = $precisePath;
} else {
$curLog->entries[$entryKey]->precisePath = $curLog->entries[$entryKey]->path;
}
}
return $curLog;
}
 
// }}}
 
function isFile($path, $rev = 0, $peg = '') {
$cmd = $this->svnCommandString('info --xml', $path, $rev, $peg);
return strpos(implode(' ', runCommand($cmd, true)), 'kind="file"') !== false;
}
 
// {{{ getSvnPath
 
function getSvnPath($path) {
if ($this->repConfig->subpath === null) {
return $this->repConfig->path.$path;
} else {
return $this->repConfig->path.'/'.$this->repConfig->subpath.$path;
}
}
 
// }}}
 
}
 
// Initialize SVN version information by parsing from command-line output.
$cmd = $config->getSvnCommand();
$cmd = str_replace(array('--non-interactive', '--trust-server-cert'), array('', ''), $cmd);
$cmd .= ' --version -q';
$ret = runCommand($cmd, false);
if (preg_match('~([0-9]+)\.([0-9]+)\.([0-9]+)~', $ret[0], $matches)) {
$config->setSubversionVersion($matches[0]);
$config->setSubversionMajorVersion($matches[1]);
$config->setSubversionMinorVersion($matches[2]);
}
/WebSVN/include/template.php
0,0 → 1,321
<?php
// WebSVN - Subversion repository viewing via the web using PHP
// Copyright (C) 2004-2006 Tim Armes
//
// 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; either version 2 of the License, or
// (at your option) any later version.
//
// 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; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// --
//
// templates.php
//
// Templating system to allow advanced page customisation
 
$vars['version'] = $version; // Set WebSVN version for all template files
$vars['currentyear'] = date('Y');
 
$ignore = false;
 
// Stack of previous test results
$ignorestack = array();
 
// Number of test levels currently ignored
$ignorelevel = 0;
 
// parseCommand
//
// Parse a special command
 
function parseCommand($line, $vars, $handle) {
global $ignore, $ignorestack, $ignorelevel, $config, $listing, $vars;
 
// process content of included file
if (strncmp(trim($line), '[websvn-include:', 16) == 0) {
if (!$ignore) {
$line = trim($line);
$file = substr($line, 16, -1);
parseTemplate($file);
}
return true;
}
 
 
// Check for test conditions
if (strncmp(trim($line), '[websvn-test:', 13) == 0) {
if (!$ignore) {
$line = trim($line);
$var = substr($line, 13, -1);
$neg = ($var[0] == '!');
if ($neg) $var = substr($var, 1);
if (empty($vars[$var]) ^ $neg) {
array_push($ignorestack, $ignore);
$ignore = true;
}
} else {
$ignorelevel++;
}
return true;
}
 
if (strncmp(trim($line), '[websvn-else]', 13) == 0) {
if ($ignorelevel == 0) {
$ignore = !$ignore;
}
return true;
}
 
if (strncmp(trim($line), '[websvn-endtest]', 16) == 0) {
if ($ignorelevel > 0) {
$ignorelevel--;
} else {
$ignore = array_pop($ignorestack);
}
return true;
}
 
if (strncmp(trim($line), '[websvn-getlisting]', 19) == 0) {
global $svnrep, $path, $rev, $peg;
 
if (!$ignore) {
$svnrep->listFileContents($path, $rev, $peg);
}
return true;
}
 
if (strncmp(trim($line), '[websvn-defineicons]', 19) == 0) {
global $icons;
 
if (!isset($icons)) {
$icons = array();
}
 
// Read all the lines until we reach the end of the definition, storing
// each one...
 
if (!$ignore) {
while (!feof($handle)) {
$line = trim(fgets($handle));
if (strncmp($line, '[websvn-enddefineicons]', 22) == 0) {
return true;
}
$eqsign = strpos($line, '=');
$match = substr($line, 0, $eqsign);
$def = substr($line, $eqsign + 1);
$icons[$match] = $def;
}
}
return true;
}
 
if (strncmp(trim($line), '[websvn-icon]', 13) == 0) {
global $icons, $vars;
 
if (!$ignore) {
// The current filetype should be defined my $vars['filetype']
if (!empty($icons[$vars['filetype']])) {
echo parseTags($icons[$vars['filetype']], $vars);
} else if (!empty($icons['*'])) {
echo parseTags($icons['*'], $vars);
}
}
 
return true;
}
 
if (strncmp(trim($line), '[websvn-treenode]', 17) == 0) {
global $icons, $vars;
 
if (!$ignore) {
if ((!empty($icons['i-node'])) && (!empty($icons['t-node'])) && (!empty($icons['l-node']))) {
for ($n = 1; $n < $vars['level']; $n++) {
if ($vars['last_i_node'][$n]) {
echo parseTags($icons['e-node'], $vars);
} else {
echo parseTags($icons['i-node'], $vars);
}
}
 
if ($vars['level'] != 0) {
if ($vars['node'] == 0) {
echo parseTags($icons['t-node'], $vars);
} else {
echo parseTags($icons['l-node'], $vars);
$vars['last_i_node'][$vars['level']] = true;
}
}
}
}
return true;
}
return false;
}
 
// parseTemplate
//
// Parse the given template, replacing the variables with the values passed
 
function parseTemplate($file) {
global $ignore, $rep, $config, $vars, $listing;
 
$template = (($rep) ? $rep->getTemplatePath() : $config->getTemplatePath()).$file;
if (!is_file($template)) {
print 'No template file found ('.$template.')';
exit;
}
 
$handle = fopen($template, 'r');
$inListing = false;
$ignore = false;
$listLines = array();
 
while (!feof($handle)) {
$line = fgets($handle);
// Check for the end of the file list
if ($inListing) {
if (strcmp(trim($line), '[websvn-endlisting]') == 0) {
$inListing = false;
 
// For each item in the list
foreach ($listing as $listvars) {
// Copy the value for this list item into the $vars array
foreach ($listvars as $id => $value) {
$vars[$id] = $value;
}
// Output the list item
foreach ($listLines as $line) {
if (!parseCommand($line, $vars, $handle) && !$ignore) {
print parseTags($line, $vars);
}
}
}
} else if ($ignore == false) {
$listLines[] = $line;
}
} else if (parseCommand($line, $vars, $handle)) {
continue;
} else {
// Check for the start of the file list
if (strncmp(trim($line), '[websvn-startlisting]', 21) == 0) {
$inListing = true;
} else {
if ($ignore == false) {
print parseTags($line, $vars);
}
}
}
}
fclose($handle);
}
 
// parseTags
//
// Replace all occurences of [websvn:varname] with the give variable
 
function parseTags($line, $vars) {
global $lang;
 
// Replace the language strings
while (preg_match('|\[lang:([a-zA-Z0-9_]+)\]|', $line, $matches)) {
// Make sure that the variable exists
if (!isset($lang[$matches[1]])) {
$lang[$matches[1]] = '?${matches[1]}?';
}
$line = str_replace($matches[0], $lang[$matches[1]], $line);
}
 
$l = '';
// Replace the websvn variables
while (preg_match('|\[websvn:([a-zA-Z0-9_]+)\]|', $line, $matches)) {
// Find beginning
$p = strpos($line, $matches[0]);
 
// add everything up to beginning
if ($p > 0) {
$l .= substr($line, 0, $p);
}
 
// Replace variable (special token, if not exists)
$l .= isset($vars[$matches[1]]) ? $vars[$matches[1]]: ('?'.$matches[1].'?');
 
// Remove allready processed part of line
$line = substr($line, $p + strlen($matches[0]));
}
 
// Rebuild line, add remaining part of line
$line = $l.$line;
 
return $line;
}
 
 
// renderTemplate
//
// Renders the templates for the given view
 
function renderTemplate($view, $readmePath = null)
{
 
global $config, $rep, $vars, $listing, $lang, $locwebsvnhttp;
 
// Set the view in the templates variables
$vars['template'] = $view;
 
// Check if we are using a PHP powered template or the standard one
$path = !empty($rep) ? $rep->getTemplatePath() : $config->getTemplatePath();
$path = $path . 'template.php';
 
if (is_readable($path))
{
$vars['templateentrypoint'] = $path;
executePlainPhpTemplate($vars);
}
else
{
parseTemplate('header.tmpl');
flush(); // http://developer.yahoo.com/performance/rules.html#flush
parseTemplate($view . '.tmpl');
 
if (($view === 'directory') || ($view === 'log'))
{
print '<script type="text/javascript" src="'.$locwebsvnhttp.'/javascript/compare-checkboxes.js"></script>';
}
 
if ($readmePath == null)
{
parseTemplate('footer.tmpl');
return;
}
 
$svnrep = new SVNRepository($rep);
$svnrep->listReadmeContents($readmePath);
parseTemplate('footer.tmpl');
}
}
 
function executePlainPhpTemplate($vars) {
require_once $vars['templateentrypoint'];
}
 
// {{{ renderTemplate404
 
function renderTemplate404($view, $errorDetail="")
{
global $vars, $lang;
http_response_code(404);
$vars['error'] = "WebSVN 404 ".$lang[$errorDetail];
renderTemplate($view);
exit(0);
}
 
// }}}
/WebSVN/include/utils.php
0,0 → 1,477
<?php
// WebSVN - Subversion repository viewing via the web using PHP
// Copyright (C) 2004-2006 Tim Armes
//
// 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; either version 2 of the License, or
// (at your option) any later version.
//
// 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; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// --
//
// utils.php
//
// General utility commands
 
// {{{ createDirLinks
//
// Create a list of links to the current path that'll be available from the template
 
function createPathLinks($rep, $path, $rev, $peg = '') {
global $config, $lang, $vars;
 
$pathComponents = explode('/', $path);
$count = count($pathComponents);
 
// The number of links depends on the last item. It's empty if we're looking
// at a directory, and non-empty if we're looking at a file.
if (empty($pathComponents[$count - 1])) {
$limit = $count - 2;
$dir = true;
} else {
$limit = $count - 1;
$dir = false;
}
 
$passRevString = createRevAndPegString($rev, $peg);
$pathSoFar = '/';
$pathSoFarURL = $config->getURL($rep, $pathSoFar, 'dir').$passRevString;
 
$repoName = $rep->getDisplayName();
$rootName = $lang['BREADCRUMB_REPO_ROOT'];
 
$vars['path_links'] = '';
$vars['path_links_root_root'] = "<a href=\"{$pathSoFarURL}\" class=\"root\"><span>{$rootName}</span></a>";
$vars['path_links_root_repo'] = "<a href=\"{$pathSoFarURL}\" class=\"root\"><span>{$repoName}</span></a>";
$vars['path_links_root_config'] = $config->getBreadcrumbRepoRootAsRepo()
? $vars['path_links_root_repo']
: $vars['path_links_root_root'];
 
for ($n = 1; $n < $limit; $n++) {
$pathSoFar .= $pathComponents[$n].'/';
$pathSoFarURL = $config->getURL($rep, $pathSoFar, 'dir').$passRevString;
$vars['path_links'] .= '<a href="'.$pathSoFarURL.'#'.anchorForPath($pathSoFar).'">'.escape($pathComponents[$n]).'</a>/';
}
 
if (!empty($pathComponents[$n])) {
$pegrev = ($peg && $peg != $rev) ? ' <a class="peg" href="'.'?'.escape(str_replace('&peg='.$peg, '', $_SERVER['QUERY_STRING'])).'">@ '.$peg.'</a>' : '';
if ($dir) {
$vars['path_links'] .= '<span class="dir">'.escape($pathComponents[$n]).'/'.$pegrev.'</span>';
} else {
$vars['path_links'] .= '<span class="file">'.escape($pathComponents[$n]).$pegrev.'</span>';
}
}
}
 
// }}}
 
function createRevAndPegString($rev, $peg) {
$params = array();
if ($rev) $params[] = 'rev='.$rev;
if ($peg) $params[] = 'peg='.$peg;
return implode('&amp;', $params);
}
 
function createDifferentRevAndPegString($rev, $peg) {
$params = array();
if ($rev && (!$peg || $rev != $peg)) $params[] = 'rev='.$rev;
if ($peg) $params[] = 'peg='.$peg;
return implode('&amp;', $params);
}
 
function anchorForPath($path) {
global $config;
 
// (X)HMTL id/name attribute must be this format: [A-Za-z][A-Za-z0-9-_.:]*
// MD5 hashes are 32 characters, deterministic, quite collision-resistant,
// and work for any string, regardless of encoding or special characters.
if ($config->treeView)
return 'a'.md5($path);
else
return '';
}
 
// {{{ create_anchors
//
// Create links out of http:// and mailto: tags
 
// TODO: the target="_blank" nonsense should be optional (or specified by the template)
function create_anchors($text) {
$ret = $text;
 
// Match correctly formed URLs that aren't already links
$ret = preg_replace('#\b(?<!href=")([a-z]+?)://(\S*)([\w/]+)#i',
'<a href="\\1://\\2\\3" target="_blank">\\1://\\2\\3</a>',
$ret);
 
// Now match anything beginning with www, as long as it's not //www since they were matched above
$ret = preg_replace('#\b(?<!//)www\.(\S*)([\w/]+)#i',
'<a href="http://www.\\1\\2" target="_blank">www.\\1\\2</a>',
$ret);
 
// Match email addresses
$ret = preg_replace('#\b([\w\-_.]+)@([\w\-.]+)\.(\w{2,})\b#i',
'<a href="mailto:\\1@\\2.\\3">\\1@\\2.\\3</a>',
$ret);
 
return $ret;
}
 
// }}}
 
// {{{ getFullURL
 
function getFullURL($loc) {
$protocol = 'http';
 
if (isset($_SERVER['HTTP_X_FORWARDED_PROTO'])) {
$protocol = $_SERVER['HTTP_X_FORWARDED_PROTO'];
} else if (isset($_SERVER['HTTPS']) && (strtolower($_SERVER['HTTPS']) != 'off')) {
$protocol = 'https';
}
 
$port = ':'.$_SERVER['SERVER_PORT'];
if ((':80' == $port && 'http' == $protocol) || (':443' == $port && 'https' == $protocol)) {
$port = '';
}
 
if (isset($_SERVER['HTTP_X_FORWARDED_HOST'])) {
$host = $_SERVER['HTTP_X_FORWARDED_HOST'];
} else if (isset($_SERVER['HTTP_HOST'])) {
$host = $_SERVER['HTTP_HOST'];
} else if (isset($_SERVER['SERVER_NAME'])) {
$host = $_SERVER['SERVER_NAME'].$port;
} else if (isset($_SERVER['SERVER_ADDR'])) {
$host = $_SERVER['SERVER_ADDR'].$port;
} else {
print 'Unable to redirect';
exit;
}
 
// make sure we have a directory to go to
if (empty($loc)) {
$loc = '/';
} else if ($loc[0] != '/') {
$loc = '/'.$loc;
}
 
$url = $protocol . '://' . $host . $loc;
 
return $url;
}
 
// }}}
 
function xml_entities($str) {
$entities = array();
$entities['&'] = '&amp;';
$entities['<'] = '&lt;';
$entities['>'] = '&gt;';
$entities['"'] = '&quot;';
$entities['\''] = '&apos;';
return str_replace(array_keys($entities), array_values($entities), $str);
}
 
// {{{ hardspace
//
// Replace the spaces at the front of a line with hard spaces
 
// XXX: this is an unnecessary function; you can prevent whitespace from being
// trimmed via CSS (use the "white-space: pre;" properties). ~J
// in the meantime, here's an improved function (does nothing)
 
function hardspace($s) {
return '<code>' . expandTabs($s) . '</code>';
}
 
// }}}
 
function wrapInCodeTagIfNecessary($string) {
global $config;
return ($config->getUseGeshi()) ? $string : '<code>'.$string.'</code>';
}
 
// {{{ expandTabs
 
/**
* Expands the tabs in a line that may or may not include HTML.
*
* Enscript generates code with HTML, so we need to take that into account.
*
* @param string $s Line of possibly HTML-encoded text to expand
* @param int $tabwidth Tab width, -1 to use repository's default, 0 to collapse
* all tabs.
* @return string The expanded line.
* @since 2.1
*/
 
function expandTabs($s, $tabwidth = - 1) {
global $rep;
 
if ($tabwidth == -1) {
$tabwidth = $rep->getExpandTabsBy();
}
$pos = 0;
 
// Parse the string into chunks that are either 1 of: HTML tag, tab char, run of any other stuff
$chunks = preg_split('/((?:<.+?>)|(?:&.+?;)|(?:\t))/', $s, -1, PREG_SPLIT_DELIM_CAPTURE);
 
// Count the sizes of the chunks and replace tabs as we go
$chunkscount = count($chunks);
for ($i = 0; $i < $chunkscount; $i++) {
// make sure we're not dealing with an empty string
if (empty($chunks[$i])) continue;
switch ($chunks[$i][0]) {
case '<': // HTML tag: ignore its width by doing nothing
break;
 
case '&': // HTML entity: count its width as 1 char
$pos++;
break;
 
case "\t": // Tab char: replace it with a run of spaces between length tabwidth and 1
$tabsize = $tabwidth - ($pos % $tabwidth);
$chunks[$i] = str_repeat(' ', $tabsize);
$pos += $tabsize;
break;
 
default: // Anything else: just keep track of its width
$pos += strlen($chunks[$i]);
break;
}
}
 
// Put the chunks back together and we've got the original line, detabbed.
return join('', $chunks);
}
 
// }}}
 
// {{{ datetimeFormatDuration
//
// Formats a duration of seconds for display.
//
// $seconds the number of seconds until something
// $nbsp true if spaces should be replaced by nbsp
// $skipSeconds true if seconds should be omitted
//
// return the formatted duration (e.g. @c "8h 6m 1s")
 
function datetimeFormatDuration($seconds, $nbsp = false, $skipSeconds = false) {
global $lang;
 
$neg = false;
if ($seconds < 0) {
$seconds = 0 - $seconds;
$neg = true;
}
 
$qty = array();
$names = array($lang['DAYLETTER'], $lang['HOURLETTER'], $lang['MINUTELETTER']);
 
$qty[] = (int)($seconds / (60 * 60 * 24));
$seconds %= 60 * 60 * 24;
 
$qty[] = (int)($seconds / (60 * 60));
$seconds %= 60 * 60;
 
$qty[] = (int)($seconds / 60);
 
if (!$skipSeconds) {
$qty[] = (int)($seconds % 60);
$names[] = $lang['SECONDLETTER'];
}
 
$text = $neg ? '-' : '';
$any = false;
$count = count($names);
$parts = 0;
for ($i = 0; $i < $count; $i++) {
// If a "higher valued" time slot had a value or this time slot
// has a value or this is the very last entry (i.e. all values
// are 0 and we still want to print seconds)
if ($any || $qty[$i] > 0 || $i == $count - 1) {
if ($any) $text .= $nbsp ? '&nbsp;' : ' ';
$text .= $qty[$i].' '.$names[$i];
$any = true;
$parts++;
if ($parts >= 2) break;
}
}
return $text;
}
 
// }}}
 
function parseSvnTimestamp($dateString) {
// Try the simple approach of a built-in PHP function first.
$date = strtotime($dateString);
// If the resulting timestamp isn't sane, try parsing manually.
if ($date <= 0) {
$y = 0;
$mo = 0;
$d = 0;
$h = 0;
$m = 0;
$s = 0;
sscanf($dateString, '%d-%d-%dT%d:%d:%d.', $y, $mo, $d, $h, $m, $s);
 
$mo = substr('00'.$mo, -2);
$d = substr('00'.$d, -2);
$h = substr('00'.$h, -2);
$m = substr('00'.$m, -2);
$s = substr('00'.$s, -2);
$date = strtotime($y.'-'.$mo.'-'.$d.' '.$h.':'.$m.':'.$s.' GMT');
}
return $date;
}
 
// {{{ buildQuery
//
// Build parameters for url query part
 
function buildQuery($data, $separator = '&amp;', $key = '') {
if (is_object($data))
$data = get_object_vars($data);
$p = array();
foreach ($data as $k => $v) {
$k = rawurlencode($k);
if (!empty($key))
$k = $key.'['.$k.']';
if (is_array($v) || is_object($v)) {
$p[] = buildQuery($v, $separator, $k);
} else {
$p[] = $k.'='.rawurlencode($v);
}
}
return implode($separator, $p);
}
 
// }}}
 
// {{{ getUserLanguage
 
function getUserLanguage($languages, $default, $userchoice) {
global $config;
if (!$config->useAcceptedLanguages()) return $default;
 
$acceptlangs = isset($_SERVER['HTTP_ACCEPT_LANGUAGE']) ? $_SERVER['HTTP_ACCEPT_LANGUAGE'] : false;
if (!$acceptlangs)
return $default;
 
$langs = array();
$sublangs = array();
 
foreach (explode(',', $acceptlangs) as $str) {
$a = explode(';', $str, 2);
$lang = trim($a[0]);
$pos = strpos($lang, '-');
if ($pos !== false)
$sublangs[] = substr($lang, 0, $pos);
$q = 1.0;
if (count($a) == 2) {
$v = trim($a[1]);
if (substr($v, 0, 2) == 'q=')
$q = doubleval(substr($v, 2));
}
if ($userchoice)
$q *= 0.9;
$langs[$lang] = $q;
}
 
foreach ($sublangs as $l)
if (!isset($langs[$l]))
$langs[$l] = 0.1;
 
if ($userchoice)
$langs[$userchoice] = 1.0;
 
arsort($langs);
foreach ($langs as $code => $q) {
if (isset($languages[$code])) {
return $code;
}
}
 
return $default;
}
 
// }}}
 
// {{{ removeDirectory
 
function removeDirectory($dir)
{
if (!is_dir($dir))
{
return false;
}
 
$dir = rtrim($dir, '/');
$handle = dir($dir);
 
while (($file = $handle->read()) !== false)
{
if (($file == '.') || ($file == '..'))
{
continue;
}
 
$f = $dir.DIRECTORY_SEPARATOR.$file;
if (!is_link($f) && is_dir($f))
{
removeDirectory($f);
}
else
{
@unlink($f);
}
}
 
$handle->close();
@rmdir($dir);
 
return true;
}
 
// }}}
 
// {{{ tempnameWithCheck
 
function tempnamWithCheck($dir, $prefix, $rmOnShutdown = true) {
$tmp = tempnam($dir, $prefix);
 
if ($tmp && !$rmOnShutdown)
{
return $tmp;
}
if ($tmp && $rmOnShutdown)
{
register_shutdown_function('removeDirectory', $tmp);
return $tmp;
}
 
if (!$tmp && !headers_sent())
{
http_response_code(500);
error_log('Unable to create a temporary file. Either make the currently used directory ("' . $dir . '") writable for WebSVN or change the directory in the configuration.');
print 'Unable to create a temporary file. Either make the currently used directory writable for WebSVN or change the directory in the configuration.';
exit(0);
}
 
global $vars;
$vars['warning'] = 'Unable to create a temporary file. Either make the currently used directory writable for WebSVN or change the directory in the configuration.';
 
return $tmp;
}
 
// }}}
/WebSVN/include/version.php
0,0 → 1,25
<?php
// WebSVN - Subversion repository viewing via the web using PHP
// Copyright (C) 2004-2006 Tim Armes
//
// 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; either version 2 of the License, or
// (at your option) any later version.
//
// 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; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
//
// --
//
// version.php
//
// Version information
 
$version = '2.8.3';