Display an error when required filesystem functions are disabled
Display an error when required filesystem functions are disabled

--- a/include/Util.class.php
+++ b/include/Util.class.php
@@ -165,5 +165,27 @@
 		return rtrim($baseurl, "/");
 	}
 
+	/**
+	 * Tests whether a function is allowed to be called
+	 *
+	 * @param string $function functio name
+	 * @return true if allowed
+	 */
+	public static function FunctionAllowed($function)
+	{
+		if (empty($function))
+			return false;
+
+		$disabled = @ini_get('disable_functions');
+		if (!$disabled) {
+			// no disabled functions
+			// or ini_get is disabled so we can't reliably figure this out
+			return true;
+		}
+
+		$disabledlist = explode(', ', $disabled);
+		return !in_array($function, $disabledlist);
+	}
+
 }
 

--- a/include/controller/Controller_Message.class.php
+++ b/include/controller/Controller_Message.class.php
@@ -269,6 +269,13 @@
 			return sprintf('You are not authorized to access project %1$s', $exception->Project);
 		}
 
+		if ($exception instanceof GitPHP_DisabledFunctionException) {
+			if ($this->resource)
+				return sprintf($this->resource->translate('Required function %1$s has been disabled'), $exception->Function);
+
+			return sprintf('Required function %1$s has been disabled', $exception->Function);
+		}
+
 		return $exception->getMessage();
 	}
 

--- a/include/controller/Controller_Snapshot.class.php
+++ b/include/controller/Controller_Snapshot.class.php
@@ -43,6 +43,10 @@
 		$this->InitializeGitExe();
 
 		$this->InitializeProjectList();
+
+		// HACK: this needs to be done early because the snapshot controller modifies the headers before opening the archive
+		if (!GitPHP_Util::FunctionAllowed('popen'))
+			throw new GitPHP_DisabledFunctionException('popen');
 
 		if (isset($this->params['project'])) {
 			$project = $this->projectList->GetProject($this->params['project']);

--- /dev/null
+++ b/include/exception/DisabledFunctionException.class.php
@@ -1,1 +1,34 @@
+<?php
+/**
+ * Custom exception when a required function is disabled
+ *
+ * @author Christopher Han <xiphux@gmail.com>
+ * @copyright Copyright (c) 2012 Christopher Han
+ * @package GitPHP
+ * @subpackage Exception
+ */
+class GitPHP_DisabledFunctionException extends GitPHP_MessageException
+{
+	/**
+	 * Function
+	 *
+	 * @var string
+	 */
+	public $Function;
 
+	/**
+	 * Constructor
+	 *
+	 * @param string $function function
+	 * @param string $message message
+	 * @param integer $code exception code
+	 */
+	public function __construct($function, $message = '', $code = 0)
+	{
+		$this->Function = $function;
+		if (empty($message))
+			$message = sprintf('Required function %1$s has been disabled', $function);
+		parent::__construct($message, true, 500, $code);
+	}
+}
+

--- a/include/git/GitExe.class.php
+++ b/include/git/GitExe.class.php
@@ -95,6 +95,27 @@
 	protected $observers = array();
 
 	/**
+	 * Whether the exec function is allowed by the install
+	 *
+	 * @var null|boolean
+	 */
+	protected $execAllowed = null;
+
+	/**
+	 * Whether the shell_exec function is allowed by the install
+	 *
+	 * @var null|boolean
+	 */
+	protected $shellExecAllowed = null;
+
+	/**
+	 * Whether the popen function is allowed by the install
+	 *
+	 * @var null|boolean
+	 */
+	protected $popenAllowed = null;
+
+	/**
 	 * Constructor
 	 *
 	 * @param string $binary path to git binary
@@ -117,6 +138,13 @@
 	 */
 	public function Execute($projectPath, $command, $args)
 	{
+		if ($this->shellExecAllowed === null) {
+			$this->shellExecAllowed = GitPHP_Util::FunctionAllowed('shell_exec');
+			if (!$this->shellExecAllowed) {
+				throw new GitPHP_DisabledFunctionException('shell_exec');
+			}
+		}
+
 		$fullCommand = $this->CreateCommand($projectPath, $command, $args);
 
 		$this->Log('Begin executing "' . $fullCommand . '"');
@@ -140,6 +168,13 @@
 	 */
 	public function Open($projectPath, $command, $args, $mode = 'r')
 	{
+		if ($this->popenAllowed === null) {
+			$this->popenAllowed = GitPHP_Util::FunctionAllowed('popen');
+			if (!$this->popenAllowed) {
+				throw new GitPHP_DisabledFunctionException('popen');
+			}
+		}
+
 		$fullCommand = $this->CreateCommand($projectPath, $command, $args);
 
 		return popen($fullCommand, $mode);
@@ -191,6 +226,13 @@
 	 */
 	protected function ReadVersion()
 	{
+		if ($this->shellExecAllowed === null) {
+			$this->shellExecAllowed = GitPHP_Util::FunctionAllowed('shell_exec');
+			if (!$this->shellExecAllowed) {
+				throw new GitPHP_DisabledFunctionException('shell_exec');
+			}
+		}
+
 		$this->versionRead = true;
 
 		$this->version = '';
@@ -275,6 +317,13 @@
 	 */
 	public function Valid()
 	{
+		if ($this->execAllowed === null) {
+			$this->execAllowed = GitPHP_Util::FunctionAllowed('exec');
+			if (!$this->execAllowed) {
+				throw new GitPHP_DisabledFunctionException('exec');
+			}
+		}
+
 		if (empty($this->binary))
 			return false;
 

comments