13

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?

Radmilla Mustafa
  • 311
  • 1
  • 2
  • 11
  • 3
    Why don't you just call `git` with `exec()` just for the commands you need? Or whats the problem with `git`-wrappers? – KingCrunch Feb 14 '12 at 21:27
  • You don't need HTTP support, as `git` has that already. You should be cloning the remote repository to a local repository on your web server and using push/pull, as that is, after all, the way `git` works. – kitti Feb 14 '12 at 21:33
  • 1
    I do not want to do calls to exec, I am looking for a class interface. calls to exec are sloppy, they are not necessarily cross-platform, and introduces potential security vulnerabilities. A class interface running on some c lib bindings or some "pure-php" code would be preferable to running shell commands. I do need http support because the software may be running on more than one webserver, local repositories would not suffice in this case. – Radmilla Mustafa Feb 14 '12 at 22:12
  • Not sure why is this question closed since it's pretty useful and I've seen couple of other similarly tuned questions which have not been closed. Newer PHP wrapper for git client also https://github.com/czproject/git-php – lubosdz Apr 10 '21 at 17:09

3 Answers3

10

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).

kbjr
  • 1,254
  • 2
  • 10
  • 22
3

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:

  1. herzult/php-ssh
  2. 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;
    }

}
scipilot
  • 6,681
  • 1
  • 46
  • 65
0

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.

Rory O'Kane
  • 29,210
  • 11
  • 96
  • 131
Patrick
  • 3,302
  • 4
  • 28
  • 47
  • 2
    Sorry, I believe this is just a repository browser, like gitweb. It won't allow you to execute any commands, just explore the files and history. – scipilot Dec 30 '13 at 11:03