For our new site we wished to have something that shows the users we are currently working on dangerdeep and the project is not dead. A good way is to get some informations from the Sourceforge SVN repository and display them on the page. But neither the subversion plugin for PHP is installed on the Sourceforge webspace or we can access our cia.vc feed, because every in/outgoing connections are blocked for scripts by the Sourceforge firewalls. Well, there is the RSS feed provided by Sf.net and it contains commit messages but the feed is far away from being well structured and doesn’t contains all informations we want.
So what can we do? The key to our problem is the WebDAV support of subversion. While the WebDAV extension is very popular, the subset and the extensions that are used by subversion aren’t. So i decided to place these lines here for other people that have the same problem.
To retrieve the commit informations from the repository we can use the log-report command of subversions WebDAV extension. Let’s start with our WebDAV request:
$request =
'<?xml version="1.0"?>'.
'<S:log-report xmlns:S="svn:">'.
'<S:start-revision>'.$start_revision.'</S:start-revision>'.
'<S:discover-changed-paths/>'.
'</S:log-report>';
As you maybe noticed there’s a variable $start_revision. This information is needed to let the server know from which revision starting he has to submit the log. If you want to get the log for a range of revisions you can easily add a tag to the request.
Now we need to know that WebDAV is an extension to the HTTP protocol. So we have to send a HTTP request with the log-report command to the repository and recieve the log information from the server. Here’s our HTTP header:
$header = "REPORT /svnroot/dangerdeep/ HTTP/1.1\r\n". "Host: dangerdeep.svn.sourceforge.net\r\n". "Depth: 1\r\n". "Content-type: text/xml\r\n". "Content-length: ".strlen($request)."\r\n\r\n";
Nothing special here. A very simple HTTP header. The next step is to open a connection the WebDAV interface of the repository and send our header+request to the other side:
$sock = fsockopen("ssl://dangerdeep.svn.sourceforge.net", 443);
if(!$sock) return false;
if(!fputs($sock, $header.$request)) return false;
As Sf.net only provides HTTPS access to svn we need to specify the “ssl://” before the hostname. PHP will then take care of all the SSL stuff and we can easily read and write plaintext from and to the server.
If everything went fine we can now read the log from the stream and ensure that the HTTP response code is 200:
$str = stream_get_contents($sock); $code = substr($str, strpos($str, ' ')+1, 3); if($code != 200) return false;
Before we can start parsing the recived log (it’s in XML format) we need to remove all crap that is before and maybe after the XML code:
$str = substr($str, strpos($str, "<")); $str = substr($str, 0, strrpos($str, ">")+1);
That’s it! Now you can do whatever you want with the log. Putting all the code in a nice function it could look like this:
define('SVN_HOST', 'dangerdeep.svn.sourceforge.net');
define('SVN_PORT', 443);
define('SVN_ROOT', '/svnroot/dangerdeep/');
function get_log($start_revision) {
$request =
'<?xml version="1.0"?>'.
'<S:log-report xmlns:S="svn:">'.
'<S:start-revision>'.$start_revision.'</S:start-revision>'.
'<S:discover-changed-paths/>'.
'</S:log-report>';
$header =
"REPORT ".SVN_ROOT." HTTP/1.1\r\n".
"Host: ".SVN_HOST."\r\n".
"Depth: 1\r\n".
"Content-type: text/xml\r\n".
"Content-length: ".strlen($request)."\r\n\r\n";
$sock = fsockopen("ssl://".SVN_HOST, SVN_PORT);
if(!$sock) return false;
if(!fputs($sock, $header.$request)) return false;
$str = stream_get_contents($sock);
$code = substr($str, strpos($str, ' ')+1, 3);
if($code != 200) return false;
$str = substr($str, strpos($str, "<"));
$str = substr($str, 0, strrpos($str, ">")+1);
return simplexml_load_string($str);
}