For a project I am working on, we want to use git as a revision tracker for certain data we modify often. We are using php for the web frontend and we need a goo php git client to use. I have come across a handful on the internet and they all tend to have the same limitation...
There is no support for HTTP. We need to be able to push/pull to remote repositories. We also need to clone.
Ideally I am looking for something that does not use the git command (ie: wrapers to exec()) but I am willing to settle if the class works well. I have seen a C library which appears to do what I want, however the php language binding is incomplete and the http functions are labeled experimental.
Does anyone have any insight into using git and http through php?
https://github.com/kbjr/Git.php
Git.php is a wrapper class around git calls that uses proc_open
instead of exec
to run the commands. While it does not have push/pull methods, it does have a general run
method for running custom git commands, so it could be used something like this:
$repo = Git::open('/path/to/repo');
$repo->run('push origin master');
It also does have methods for cloning (clone_to
and clone_from
which do local cloning and clone_remote
for remote cloning).
One possibility is to use PHP's SSH library to perform those actions by connecting back to the web server?
Or I found this set of classes which allow you to you to clone and read other metadata over HTTP, but not push nor pull. However it could be a starting point if you're brave enough to extend them to do that. I can imagine it would be a lot of work to replicate these processes and keep them compliant with various server versions etc.
[UPDATED 23/03/2014, after receiving an upvote - thanks!]
I did get some way trying to implement the above (I was searching for an implementation, drew a blank so tried to write my own), and it was hard as I thought! I actually abandoned it as I found a simpler way to achieve this in a different architecture, but here's the class I wrote trying. It essentially works, but was brittle to the environmental variations I was working in (i.e. it doesn't cope very well with errors or problems).
It uses:
- herzult/php-ssh
- an ssh config file - a trick to simplify setting up authentication credentials in code
(Note - I had to quickly strip out a few details from the code to post it. So you'll need to fiddle about a bit to integrate it into your app/namespace etc.)
<?php
/**
* @author: scipilot
* @since: 31/12/2013
*/
/**
* Class GitSSH allows you to perform Git functions over an SSH session.
* i.e. you are using the command-line Git commands after SSHing to a host which has the Git client.
*
* You don't need to know about the SSH to use the class, other than the fact you will need access
* to a server via SSH which has the Git client installed. Its likely this is the local web server.
*
* This was made because PHP has no good native Git client.
*
* Requires herzult/php-ssh
*
* Example php-ssh config file would be
*
* <code>
* Host localhost
* User git
* IdentityFile id_rsa
*
* Host your.host.domain.com
* User whoever
* IdentityFile ~/.ssh/WhoeverGit
*</code>
*/
class GitSSH {
protected $config;
protected $session;
protected $sPath;
/**
* @var string
*/
protected $sConfigPath = '~/.ssh/config';
/**
* Connects to the specified host, ready for further commands.
*
* @param string $sHost Host (entry in the config file) to connect to.
* @param string $sConfigPath Optional; config file path. Defaults to ~/.ssh/config,
* which is probably inaccessible for web apps.
*/
function __construct($sHost, $sConfigPath=null){
\Log::info('New GitSSH '.$sHost.', '.$sConfigPath);
if(isset($sConfigPath)) $this->sConfigPath = $sConfigPath;
$this->config = new \Ssh\SshConfigFileConfiguration($this->sConfigPath, $sHost);
$this->session = new \Ssh\Session($this->config, $this->config->getAuthentication());
}
public function __destruct() {
$this->disconnect();
}
/**
* Thanks to Steve Kamerman, as there isn't a native disconnect.
*/
public function disconnect() {
$this->exec('echo "EXITING" && exit;');
$this->session = null;
}
/**
* Run a command (in the current working directory set by cd)
* @param $sCommand
* @return string
*/
protected function exec($sCommand) {
//echo "\n".$sCommand."\n";
$exec = $this->session->getExec();
$result = $exec->run('cd '.$this->sPath.'; '.$sCommand);
// todo: parse/scrape the result, return a Result object?
return $result;
}
/**
* CD to a folder. (This not an 'incremental' cd!)
* Devnote: we don't really execute the cd now, it's appended to other commands. Each command seems to re-login?
*
* @param string $sPath Absolute filesystem path, or relative from user home
*/
public function cd($sPath){
$this->sPath = $sPath;
// @todo this is useless! each command seems to run in a separate login?
//$result = $this->exec('cd'); // /; ls');
//return $result;
}
/**
* @return string
*/
public function ls(){
$result = $this->exec('ls ');
return $result;
}
public function gitAdd($sOptions=null, array $aFiles=null){
$result = $this->exec('git add '
.(empty($sOptions) ? '' : ' '.$sOptions)
.(empty($aFiles) ? '' : ' '.implode(' ', $aFiles))
);
return $result;
}
public function gitClone($sRepo, $sBranch=null, $sTarget=null){
\Log::info('GitSSH::clone '.$sRepo.', '.$sBranch.', '.$sTarget);
$result = $this->exec('git clone '
.(empty($sBranch) ? '' : ' --branch '.$sBranch)
.' '.$sRepo
.' '.$sTarget);
return $result;
}
public function gitCommit($sMessage, $sOptions=null, array $aFiles=null){
$result = $this->exec('git commit '
.'-m "'.addcslashes($sMessage, '"').'"'
.(empty($sOptions) ? '' : ' '.$sOptions)
.(empty($aFiles) ? '' : ' '.implode(' ', $aFiles))
);
return $result;
}
public function gitPull($sOptions=null, $sRepo=null, $sRefspec=null){
$result = $this->exec('git pull '
.(empty($sOptions) ? '' : ' '.$sOptions)
.(empty($sRepo) ? '' : ' '.$sRepo)
.(empty($sRefspec) ? '' : ' '.$sRefspec)
);
return $result;
}
public function gitPush($sOptions=null, $sRepo=null, $sRefspec=null){
$result = $this->exec('git push '
.(empty($sOptions) ? '' : ' '.$sOptions)
.(empty($sRepo) ? '' : ' '.$sRepo)
.(empty($sRefspec) ? '' : ' '.$sRefspec)
);
return $result;
}
/**
* @return string the raw result from git status
*/
public function gitStatus(){
$result = $this->exec('git status');
return $result;
}
}
This looks promising: http://gitphp.org (broken link; see an archived version)
I think that will do it for you. Here is the description of it:
GitPHP is a web frontend for git repositories. It emulates the look of standard gitweb, but is written in PHP and makes use of Smarty templates for customization. It has a couple extras, including syntax highlighting through the GeSHi PHP class and project category support. It works with standard git as well as msysgit on Windows.
Setup should be fairly simple – just extract the tarball where you want to install it, copy config/gitphp.conf.php.example to config/gitphp.conf.php, and set the projectroot in the conf to point to your directory where your bare git repositories are, and make the templates_c directory writeable by the webserver if it’s not already.
You can look through all the available options and defaults in config/gitphp.conf.defaults.php, and copy an option into your config file if you want to override the default. You can also copy config/projects.conf.php.example to config/projects.conf.php and edit it if you want more advanced control over your projects, such as defining categories for projects or loading projects from a text file. More detailed instructions are in the included README.
Note: if you’re upgrading your existing gitphp.conf.php will not be overwritten, but I recommend checking gitphp.conf.defaults.php for new configuration options that may have been added.
You can view the live copy running on this site.