Skip to content

Instantly share code, notes, and snippets.

@indrakaw
Last active June 20, 2019 03:08
Show Gist options
  • Save indrakaw/8eedd1ffce4d6046e81f5f8f72ad0370 to your computer and use it in GitHub Desktop.
Save indrakaw/8eedd1ffce4d6046e81f5f8f72ad0370 to your computer and use it in GitHub Desktop.
A collection of function for git hash checking in PHP. Pure PHP, no command exec() required.
<?php
/**
* Git Helper
*
* This file contains set of functions that returns git's metadata.
* It doesn't perform git operation; read then pharse only.
*
* LIMITATION: this function only read local object (branch, tag).
* You have to fetch remote object first (eg. `git fetch --all`).
* Best use on shared web hosting and enviorment with exploitable
* funtions disabled: shell_exec(), exec(), eval(), system(), etc.
*
* $git_root param is relative to frontend file (index.php).
* eg. "is_git('.');" will check the dir of index.php.
*
* Set $git_root param to NULL, it will use APPPATH.
*
* @author Indra Kurniawan <indekaw@teknik.io>
* @copyright 2019 Indra Kurniawan
* @version 1.0.0
*/
// This's a helper of designed for CodeIgniter. If you are having problem
// accesing it, you should comment out or remove a line bellow.
defined('BASEPATH') or exit('No direct script access allowed');
/**
* Determinte is application is run undergit.
*
* @param string $git_root
* @param boolean $check_parent
* @return boolean|string FALSE or path to path to HEAD file
*/
function is_git($git_root = NULL, $check_parent = FALSE)
{
if (is_null($git_root)) {
if (defined(APPPATH)) {
// This's a helper of CodeIgniter, so...
$git_root = APPPATH;
} else {
$git_root = '.';
}
}
if (file_exists($head_path = $git_root . '/.git/HEAD')) {
return $head_path;
}
if ($check_parent && (file_exists($head_path = $git_root . '/../.git/HEAD'))) {
return $head_path;
}
return FALSE;
}
/**
* Return referenced path of HEAD
*
* @param string $git_root
* @param boolean $check_parent
* @return boolean|string FALSE or ref path string
*/
function git_ref($git_root = NULL, $check_parent = FALSE)
{
// Is valid?
if (($head_path = is_git($git_root, $check_parent)) === FALSE) {
return FALSE;
}
// Does HEAD contain ref?
if (strpos($head_content = @file_get_contents($head_path), 'ref:') === 0) {
$head_ref = trim(str_replace('ref:', '', trim($head_content)));
return sprintf(dirname($head_path).'/%s', $head_ref);
}
return FALSE;
}
/**
* Check whatever the HEAD file refer to a branch or not.
* This implies git_ref();
*
* @param string $git_root
* @param boolean $check_parent
* @return boolean|string FALSE or path to branch's name
*/
function git_branch($git_root = NULL, $check_parent = FALSE)
{
// Validate git then return HEAD's ref.
if (($ref_head = git_ref($git_root, $check_parent)) === FALSE) {
return FALSE;
}
// Does ref contain branch path?
if (strpos($ref_head, '.git/refs/heads/') !== FALSE) {
return $ref_head;
}
return FALSE;
}
/**
* Check whatever the HEAD file refer to a tag or not.
* This implies git_ref();
*
* @param string $git_root
* @param boolean $check_parent
* @return boolean|string FALSE or path to tag's name
*/
function git_tag($git_root = NULL, $check_parent = FALSE)
{
// Validate git then return HEAD's ref.
if (($ref_head = git_ref($git_root, $check_parent)) === FALSE) {
return FALSE;
}
// Does ref contain tag path?
if (strpos($ref_head, '.git/refs/tags/') !== FALSE) {
return $ref_head;
}
return FALSE;
}
/**
* Return hash of HEAD file
*
* @param string $git_root
* @param boolean $check_parent
* @return boolean|string FALSE or HEAD's hash
*/
function git_hash($git_root = NULL, $check_parent = FALSE)
{
// Is head a ref?
if ($head_ref = git_ref($git_root, $check_parent)) {
return trim(@file_get_contents($head_ref));
}
// Assume HEAD contains the hash.
if ($head_path = is_git($git_root, $check_parent)) {
return trim(@file_get_contents($head_path));
}
// Maybe it isn't a git.
return FALSE;
}
/**
* Return the refferenced branch (or tag) of HEAD's hash.
* Best use for `git checkout <branch>` instead of ugly hash.
*
* @param string $git_root
* @param boolean $check_parent
* @return boolean|string FALSE or head's ref (branch or tag) name
*/
function git_head($git_root = NULL, $check_parent = FALSE)
{
// Is head a ref?
if ($head_ref = git_ref($git_root, $check_parent)) {
return basename($head_ref);
}
// Lookup for refs by HEAD's hash.
if (!$head_path = is_git($git_root, $check_parent)) {
return FALSE;
}
// Let's see which branch or tags has this hash (no pun needed)/
$object_list = array();
$object_list = glob(dirname($head_path) . '/refs/{heads,tags}/*', GLOB_BRACE);
// A repo basically has a branch, if isn't then it's an empty repo (has no commit)
if (empty($object_list)) {
return FALSE;
}
// Looping throught array of files within read its contents isn't that slow.
// They are branches and tags files, a popular git repo usually has around 60 of them.
$hash = trim(@file_get_contents(trim($head_path)));
foreach ($object_list as $file) {
if ((trim(@file_get_contents(trim($file)))) === $hash) {
// return only first found
return basename($file);
}
}
// Maybe it isn't a git or hash has no refs
return FALSE;
}
<?php
/**
* Example file
*
* Run this example script by command-line interface (no web-server required):
* $ cd path/to/this/file/
* $ php ./procedural_example.php
*/
// Define BASEPATH (required, for to prevent direct access).
define('BASEPATH', '');
// Load the helper
require_once 'git_helper.php';
// Set repo is on curent dir relatively to this file (procedural_example.php)
// You might set this to magic constants __DIR__, etc.
$path = '.';
// No need to check the parent
$check_parent = FALSE;
var_dump($path);
var_dump($check_parent);
echo '=================' . PHP_EOL;
echo 'is_get: ';
var_dump(is_git($path, $check_parent));
echo 'head\'s content: ';
var_dump(@file_get_contents(is_git($path, $check_parent)));
echo '=================' . PHP_EOL;
echo 'git_branch: ';
var_dump(git_branch($path, $check_parent));
echo 'git_tag: ';
var_dump(git_tag($path, $check_parent));
echo 'git_hash: ';
var_dump(git_hash($path, $check_parent));
echo 'git_ref: ';
var_dump(git_ref($path, $check_parent));
// EOF
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment