//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/mime_content_type.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/strripos.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/var_export.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/fputcsv.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/array_diff_assoc.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/pg_affected_rows.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/bcinvert.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_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/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/image_type_to_mime_type.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_uintersect_uassoc.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/ini_get_all.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/fprintf.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/vsprintf.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/call_user_func_array.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/scandir.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/vprintf.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/file_get_contents.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/inet_ntop.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/debug_print_backtrace.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/ibase_timefmt.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_word_count.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_diff_key.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/array_walk_recursive.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/str_shuffle.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/strpbrk.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/constant.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/str_rot13.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/time_sleep_until.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/html_entity_decode.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/array_udiff_uassoc.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/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/bcpowmod.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/is_a.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/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['&'] = '&'; |
$entities['<'] = '<'; |
$entities['>'] = '>'; |
$entities['"'] = '"'; |
$entities['\''] = '''; |
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).'&'; |
} |
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', ' ', '-', 'diffempty'); |
} |
function addAddedLine($text, $lineno) { |
$this->_add(' ', '-', '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 = ' '; |
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 = ' '; |
} |
if ($curnline < $nline) { |
$text2 = getWrappedLineFromFile($nfile, $highlighted); |
$tmpnline = $curnline; |
$curnline++; |
} else { |
$tmpnline = '?'; |
$text2 = ' '; |
} |
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 = ' '; |
} |
$text2 = getWrappedLineFromFile($nfile, $highlighted); |
if ($text2 !== false) { |
$tmpnline = $curnline; |
$curnline++; |
$noneof = true; |
} else { |
$tmpnline = '-'; |
$text2 = ' '; |
} |
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].' – '.$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('[', '[', str_replace(']', ']', $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('&', $params); |
} |
function createDifferentRevAndPegString($rev, $peg) { |
$params = array(); |
if ($rev && (!$peg || $rev != $peg)) $params[] = 'rev='.$rev; |
if ($peg) $params[] = 'peg='.$peg; |
return implode('&', $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['&'] = '&'; |
$entities['<'] = '<'; |
$entities['>'] = '>'; |
$entities['"'] = '"'; |
$entities['\''] = '''; |
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 ? ' ' : ' '; |
$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 = '&', $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'; |