Add option to generate abbreviated hashes in urls
Add option to generate abbreviated hashes in urls

--- a/config/gitphp.conf.defaults.php
+++ b/config/gitphp.conf.defaults.php
@@ -256,6 +256,21 @@
  */
 $gitphp_conf['graphs'] = false;
 
+/*
+ * abbreviateurl
+ * Generates urls using abbreviated hashes instead of
+ * full hashes.
+ * Note that urls with abbreviated hashes are not safe
+ * to be saved long term (eg bookmarks), as future objects
+ * may be added to the repository that cause an abbreviated
+ * hash to no longer be unique.
+ * This option only takes effect with the 'compat' option
+ * turned off.
+ * Additionally, this option will automatically enable
+ * 'uniqueabbrev', as an abbreviated hash must be unique
+ * in order to resolve it to a full hash.
+ */
+$gitphp_conf['abbreviateurl'] = false;
 
 
 /*********************************************************

--- a/include/Router.class.php
+++ b/include/Router.class.php
@@ -257,8 +257,9 @@
 	 *
 	 * @param string $baseurl base request url
 	 * @param array $params request parameters
+	 * @param boolean $abbreviate true to abbreviate url hashes
 	 */
-	public static function GetUrl($baseurl, $params = array())
+	public static function GetUrl($baseurl, $params = array(), $abbreviate = false)
 	{
 		if (count($params) < 1)
 			return $baseurl;
@@ -272,16 +273,19 @@
 		}
 
 		if (!empty($params['project'])) {
-			if ($params['project'] instanceof GitPHP_Project)
+			if ($params['project'] instanceof GitPHP_Project) {
 				$query['p'] = rawurlencode($params['project']->GetProject());
-			else if (is_string($params['project']))
+				if ($abbreviate && $params['project']->GetCompat())
+					$abbreviate = false;
+			} else if (is_string($params['project'])) {
 				$query['p'] = rawurlencode($params['project']);
+			}
 		}
 
 		switch ($action) {
 			case 'search':
 				if (!empty($params['hash']))
-					$query['h'] = GitPHP_Router::GetHash($params['hash']);
+					$query['h'] = GitPHP_Router::GetHash($params['hash'], $abbreviate);
 				if (!empty($params['page']))
 					$query['pg'] = $params['page'];
 				if (!empty($params['search']))
@@ -294,9 +298,9 @@
 			case 'commitdiff':
 			case 'commitdiff_plain':
 				if (!empty($params['hash']))
-					$query['h'] = GitPHP_Router::GetHash($params['hash']);
+					$query['h'] = GitPHP_Router::GetHash($params['hash'], $abbreviate);
 				if (!empty($params['hashparent']))
-					$query['hp'] = GitPHP_Router::GetHash($params['hashparent']);
+					$query['hp'] = GitPHP_Router::GetHash($params['hashparent'], $abbreviate);
 				if (!empty($params['diffmode']))
 					$query['d'] = $params['diffmode'];
 				if (!empty($params['output']))
@@ -311,11 +315,11 @@
 				if (!empty($params['file']))
 					$query['f'] = rawurlencode($params['file']);
 				if (!empty($params['hash']))
-					$query['h'] = GitPHP_Router::GetHash($params['hash']);
+					$query['h'] = GitPHP_Router::GetHash($params['hash'], $abbreviate);
 				if (!empty($params['hashbase']))
-					$query['hb'] = GitPHP_Router::GetHash($params['hashbase']);
+					$query['hb'] = GitPHP_Router::GetHash($params['hashbase'], $abbreviate);
 				if (!empty($params['hashparent']))
-					$query['hp'] = GitPHP_Router::GetHash($params['hashparent']);
+					$query['hp'] = GitPHP_Router::GetHash($params['hashparent'], $abbreviate);
 				if (!empty($params['output']))
 					$query['o'] = $params['output'];
 				break;
@@ -323,7 +327,7 @@
 
 			case 'history':
 				if (!empty($params['hash']))
-					$query['h'] = GitPHP_Router::GetHash($params['hash']);
+					$query['h'] = GitPHP_Router::GetHash($params['hash'], $abbreviate);
 				if (!empty($params['file']))
 					$query['f'] = rawurlencode($params['file']);
 				break;
@@ -332,17 +336,17 @@
 			case 'shortlog':
 			case 'log':
 				if (!empty($params['hash']))
-					$query['h'] = GitPHP_Router::GetHash($params['hash']);
+					$query['h'] = GitPHP_Router::GetHash($params['hash'], $abbreviate);
 				if (!empty($params['page']))
 					$query['pg'] = $params['page'];
 				if (!empty($params['mark']))
-					$query['m'] = GitPHP_Router::GetHash($params['mark']);
+					$query['m'] = GitPHP_Router::GetHash($params['mark'], $abbreviate);
 				break;
 
 
 			case 'snapshot':
 				if (!empty($params['hash']))
-					$query['h'] = GitPHP_Router::GetHash($params['hash']);
+					$query['h'] = GitPHP_Router::GetHash($params['hash'], $abbreviate);
 				if (!empty($params['path']))
 					$query['f'] = rawurlencode($params['path']);
 				if (!empty($params['prefix']))
@@ -356,9 +360,9 @@
 				if (!empty($params['file']))
 					$query['f'] = rawurlencode($params['file']);
 				if (!empty($params['hash']))
-					$query['h'] = GitPHP_Router::GetHash($params['hash']);
+					$query['h'] = GitPHP_Router::GetHash($params['hash'], $abbreviate);
 				if (!empty($params['hashbase']))
-					$query['hb'] = GitPHP_Router::GetHash($params['hashbase']);
+					$query['hb'] = GitPHP_Router::GetHash($params['hashbase'], $abbreviate);
 				if (!empty($params['output']))
 					$query['o'] = $params['output'];
 				break;
@@ -379,11 +383,11 @@
 
 			case 'blame':
 				if (!empty($params['hashbase']))
-					$query['hb'] = GitPHP_Router::GetHash($params['hashbase']);
+					$query['hb'] = GitPHP_Router::GetHash($params['hashbase'], $abbreviate);
 				if (!empty($params['file']))
 					$query['f'] = rawurlencode($params['file']);
 				if (!empty($params['hash']))
-					$query['h'] = GitPHP_Router::GetHash($params['hash']);
+					$query['h'] = GitPHP_Router::GetHash($params['hash'], $abbreviate);
 				if (!empty($params['output']))
 					$query['o'] = $params['output'];
 				break;
@@ -392,11 +396,11 @@
 			case 'blob':
 			case 'blob_plain':
 				if (!empty($params['hashbase']))
-					$query['hb'] = GitPHP_Router::GetHash($params['hashbase']);
+					$query['hb'] = GitPHP_Router::GetHash($params['hashbase'], $abbreviate);
 				if (!empty($params['file']))
 					$query['f'] = rawurlencode($params['file']);
 				if (!empty($params['hash']))
-					$query['h'] = GitPHP_Router::GetHash($params['hash']);
+					$query['h'] = GitPHP_Router::GetHash($params['hash'], $abbreviate);
 				if (!empty($params['output']))
 					$query['o'] = $params['output'];
 				break;
@@ -404,7 +408,7 @@
 
 			case 'commit':
 				if (!empty($params['hash']))
-					$query['h'] = GitPHP_Router::GetHash($params['hash']);
+					$query['h'] = GitPHP_Router::GetHash($params['hash'], $abbreviate);
 				if (!empty($params['output']))
 					$query['o'] = $params['output'];
 				break;
@@ -450,14 +454,15 @@
 	 * Gets a hash for a string or hash-identified object
 	 *
 	 * @param string|GitPHP_GitObject $value string or hashed object
+	 * @param boolean $abbreviate true to abbreviate hash
 	 * @return string hash
 	 */
-	private static function GetHash($value)
+	private static function GetHash($value, $abbreviate = false)
 	{
 		if ($value instanceof GitPHP_Ref)
 			return rawurlencode($value->GetRefPath());
 		else if ($value instanceof GitPHP_GitObject)
-			return $value->GetHash();
+			return $value->GetHash($abbreviate);
 		else if (is_string($value))
 			return $value;
 

--- a/include/controller/ControllerBase.class.php
+++ b/include/controller/ControllerBase.class.php
@@ -510,6 +510,10 @@
 		$this->tpl->assign('scripturl', $scripturl);
 		$this->tpl->assign('fullscripturl', $fullscripturl);
 
+		if ($this->config->GetValue('abbreviateurl')) {
+			$this->tpl->assign('abbreviateurl', true);
+		}
+
 		$getvars = explode('&', $_SERVER['QUERY_STRING']);
 		$getvarsmapped = array();
 		foreach ($getvars as $varstr) {

--- a/include/git/GitObjectManager.class.php
+++ b/include/git/GitObjectManager.class.php
@@ -162,9 +162,18 @@
 	 */
 	public function GetCommit($hash)
 	{
+		if (empty($hash))
+			return null;
+
+		if (preg_match('/^[0-9A-Fa-f]{4,39}$/', $hash)) {
+			$fullHash = $this->project->ExpandHash($hash);
+			if ($fullHash == $hash)
+				throw new GitPHP_InvalidHashException($hash);
+			$hash = $fullHash;
+		}
+
 		if (!preg_match('/^[0-9A-Fa-f]{40}$/', $hash))
 			return null;
-
 
 		$key = GitPHP_Commit::CacheKey($this->project->GetProject(), $hash);
 
@@ -288,6 +297,16 @@
 		if (empty($hash))
 			return null;
 
+		if (preg_match('/^[0-9A-Fa-f]{4,39}$/', $hash) && !$this->compat) {
+			$fullHash = $this->project->ExpandHash($hash);
+			if ($fullHash == $hash)
+				throw new GitPHP_InvalidHashException($hash);
+			$hash = $fullHash;
+		}
+
+		if (!preg_match('/^[0-9A-Fa-f]{40}$/', $hash))
+			return null;
+
 		$key = GitPHP_Blob::CacheKey($this->project->GetProject(), $hash);
 
 		$blob = null;
@@ -332,6 +351,16 @@
 	public function GetTree($hash)
 	{
 		if (empty($hash))
+			return null;
+
+		if (preg_match('/^[0-9A-Fa-f]{4,39}$/', $hash) && !$this->compat) {
+			$fullHash = $this->project->ExpandHash($hash);
+			if ($fullHash == $hash)
+				throw new GitPHP_InvalidHashException($hash);
+			$hash = $fullHash;
+		}
+
+		if (!preg_match('/^[0-9A-Fa-f]{40}$/', $hash))
 			return null;
 
 		$key = GitPHP_Tree::CacheKey($this->project->GetProject(), $hash);

--- a/include/git/project/Project.class.php
+++ b/include/git/project/Project.class.php
@@ -726,10 +726,7 @@
 		}
 
 		if (preg_match('/^[0-9A-Fa-f]{4,39}$/', $hash)) {
-			$fullHash = $this->ExpandHash($hash);
-			if ($fullHash == $hash)
-				throw new GitPHP_InvalidHashException($hash);
-			return $this->GetCommit($fullHash);
+			return $this->GetObjectManager()->GetCommit($hash);
 		}
 
 		return null;

--- a/include/git/projectlist/ProjectListBase.class.php
+++ b/include/git/projectlist/ProjectListBase.class.php
@@ -433,6 +433,10 @@
 
 		if ($this->config->HasKey('uniqueabbrev')) {
 			$project->SetUniqueAbbreviation($this->config->GetValue('uniqueabbrev'));
+		}
+
+		if ($this->config->GetValue('abbreviateurl')) {
+			$project->SetUniqueAbbreviation(true);
 		}
 	}
 

--- a/include/smartyplugins/function.geturl.php
+++ b/include/smartyplugins/function.geturl.php
@@ -36,7 +36,9 @@
 		$escape = true;
 	unset($params['escape']);
 
-	$fullurl = GitPHP_Router::GetUrl($url, $params);
+	$abbreviate = $template->getTemplateVars('abbreviateurl');
+
+	$fullurl = GitPHP_Router::GetUrl($url, $params, $abbreviate);
 	if ($escape)
 		$fullurl = htmlspecialchars($fullurl);
 

--- a/templates/commit.tpl
+++ b/templates/commit.tpl
@@ -94,7 +94,7 @@
 	 
        {if $diffline->GetStatus() == "A"}
          <td>
-	   <a href="{geturl project=$project action=blob hash=$diffline->GetToHash() hashbase=$commit file=$diffline->GetFromFile()}" class="list">
+	   <a href="{geturl project=$project action=blob hash=$diffline->GetToBlob() hashbase=$commit file=$diffline->GetFromFile()}" class="list">
 	     {$diffline->GetFromFile()}
 	   </a>
 	 </td>
@@ -112,14 +112,14 @@
 	   </span>
 	 </td>
          <td class="link">
-	   <a href="{geturl project=$project action=blob hash=$diffline->GetToHash() hashbase=$commit file=$diffline->GetFromFile()}">{t}blob{/t}</a>
+	   <a href="{geturl project=$project action=blob hash=$diffline->GetToBlob() hashbase=$commit file=$diffline->GetFromFile()}">{t}blob{/t}</a>
 	    | 
-	   <a href="{geturl project=$project action=blob hash=$diffline->GetToHash() file=$diffline->GetFromFile() output=plain}">{t}plain{/t}</a>
+	   <a href="{geturl project=$project action=blob hash=$diffline->GetToBlob() file=$diffline->GetFromFile() output=plain}">{t}plain{/t}</a>
 	 </td>
        {elseif $diffline->GetStatus() == "D"}
          {assign var=parent value=$commit->GetParent()}
          <td>
-	   <a href="{geturl project=$project action=blob hash=$diffline->GetFromHash() hashbase=$commit file=$diffline->GetFromFile()}" class="list">
+	   <a href="{geturl project=$project action=blob hash=$diffline->GetFromBlob() hashbase=$commit file=$diffline->GetFromFile()}" class="list">
 	     {$diffline->GetFromFile()}
 	   </a>
 	 </td>
@@ -130,20 +130,20 @@
 	   </span>
 	 </td>
          <td class="link">
-	   <a href="{geturl project=$project action=blob hash=$diffline->GetFromHash() hashbase=$commit file=$diffline->GetFromFile()}">{t}blob{/t}</a>
+	   <a href="{geturl project=$project action=blob hash=$diffline->GetFromBlob() hashbase=$commit file=$diffline->GetFromFile()}">{t}blob{/t}</a>
 	    | 
 	   <a href="{geturl project=$project action=history hash=$parent file=$diffline->GetFromFile()}">{t}history{/t}</a>
 	    | 
-	   <a href="{geturl project=$project action=blob hash=$diffline->GetFromHash() file=$diffline->GetFromFile() output=plain}">{t}plain{/t}</a>
+	   <a href="{geturl project=$project action=blob hash=$diffline->GetFromBlob() file=$diffline->GetFromFile() output=plain}">{t}plain{/t}</a>
 	 </td>
        {elseif $diffline->GetStatus() == "M" || $diffline->GetStatus() == "T"}
          <td>
            {if $diffline->GetToHash() != $diffline->GetFromHash()}
-             <a href="{geturl project=$project action=blobdiff hash=$diffline->GetToHash() hashparent=$diffline->GetFromHash() hashbase=$commit file=$diffline->GetToFile()}" class="list">
+             <a href="{geturl project=$project action=blobdiff hash=$diffline->GetToBlob() hashparent=$diffline->GetFromBlob() hashbase=$commit file=$diffline->GetToFile()}" class="list">
 	       {$diffline->GetToFile()}
 	     </a>
            {else}
-             <a href="{geturl project=$project action=blob hash=$diffline->GetToHash() hashbase=$commit file=$diffline->GetToFile()}" class="list">
+             <a href="{geturl project=$project action=blob hash=$diffline->GetToBlob() hashbase=$commit file=$diffline->GetToFile()}" class="list">
 	       {$diffline->GetToFile()}
 	     </a>
            {/if}
@@ -190,22 +190,22 @@
 	   {/if}
 	 </td>
          <td class="link">
-           <a href="{geturl project=$project action=blob hash=$diffline->GetToHash() hashbase=$commit file=$diffline->GetToFile()}">{t}blob{/t}</a>
+           <a href="{geturl project=$project action=blob hash=$diffline->GetToBlob() hashbase=$commit file=$diffline->GetToFile()}">{t}blob{/t}</a>
 	   {if $diffline->GetToHash() != $diffline->GetFromHash()}
-	     | <a href="{geturl project=$project action=blobdiff hash=$diffline->GetToHash() hashparent=$diffline->GetFromHash() hashbase=$commit file=$diffline->GetToFile()}">{t}diff{/t}</a>
+	     | <a href="{geturl project=$project action=blobdiff hash=$diffline->GetToBlob() hashparent=$diffline->GetFromBlob() hashbase=$commit file=$diffline->GetToFile()}">{t}diff{/t}</a>
 	   {/if}
 	     | <a href="{geturl project=$project action=history hash=$commit file=$diffline->GetFromFile()}">{t}history{/t}</a>
-             | <a href="{geturl project=$project action=blob hash=$diffline->GetToHash() file=$diffline->GetToFile() output=plain}">{t}plain{/t}</a>
+             | <a href="{geturl project=$project action=blob hash=$diffline->GetToBlob() file=$diffline->GetToFile() output=plain}">{t}plain{/t}</a>
 	 </td>
        {elseif $diffline->GetStatus() == "R"}
          <td>
-	   <a href="{geturl project=$project action=blob hash=$diffline->GetToHash() hashbase=$commit file=$diffline->GetToFile()}" class="list">
+	   <a href="{geturl project=$project action=blob hash=$diffline->GetToBlob() hashbase=$commit file=$diffline->GetToFile()}" class="list">
 	     {$diffline->GetToFile()}</a>
 	 </td>
          <td>
 	   <span class="movedfile">
 	     {capture assign=fromfilelink}
-	     <a href="{geturl project=$project action=blob hash=$diffline->GetFromHash() hashbase=$commit file=$diffline->GetFromFile()}" class="list">{$diffline->GetFromFile()}</a>
+	     <a href="{geturl project=$project action=blob hash=$diffline->GetFromBlob() hashbase=$commit file=$diffline->GetFromFile()}" class="list">{$diffline->GetFromFile()}</a>
 	     {/capture}
 	     [
 	     {assign var=similarity value=$diffline->GetSimilarity()}
@@ -219,11 +219,11 @@
 	   </span>
 	 </td>
          <td class="link">
-	   <a href="{geturl project=$project action=blob hash=$diffline->GetToHash() hashbase=$commit file=$diffline->GetToFile()}">{t}blob{/t}</a>
+	   <a href="{geturl project=$project action=blob hash=$diffline->GetToBlob() hashbase=$commit file=$diffline->GetToFile()}">{t}blob{/t}</a>
 	   {if $diffline->GetToHash() != $diffline->GetFromHash()}
-	     | <a href="{geturl project=$project action=blobdiff hash=$diffline->GetToHash() hashparent=$diffline->GetFromHash() hashbase=$commit file=$diffline->GetToFile()}">{t}diff{/t}</a>
+	     | <a href="{geturl project=$project action=blobdiff hash=$diffline->GetToBlob() hashparent=$diffline->GetFromBlob() hashbase=$commit file=$diffline->GetToFile()}">{t}diff{/t}</a>
 	   {/if}
-	    | <a href="{geturl project=$project action=blob hash=$diffline->GetToHash() file=$diffline->GetToFile() output=plain}">{t}plain{/t}</a>
+	    | <a href="{geturl project=$project action=blob hash=$diffline->GetToBlob() file=$diffline->GetToFile() output=plain}">{t}plain{/t}</a>
 	 </td>
        {/if}
 

comments