diff --git a/lib/private/app.php b/lib/private/app.php
index 8e36d43bfb1eef51d863806ba60aa3a6f0d72f61..86db8fd9f55e90853ef116e144c2ca2638aa7fa7 100644
--- a/lib/private/app.php
+++ b/lib/private/app.php
@@ -809,7 +809,7 @@ class OC_App {
 
 				if(isset($info['shipped']) and ($info['shipped'] == 'true')) {
 					$info['internal'] = true;
-					$info['internallabel'] = $l->t('Recommended');
+					$info['internallabel'] = (string)$l->t('Recommended');
 					$info['internalclass'] = 'recommendedapp';
 					$info['removable'] = false;
 				} else {
@@ -920,7 +920,7 @@ class OC_App {
 			$app1[$i]['score'] = $app['score'];
 			$app1[$i]['removable'] = false;
 			if ($app['label'] == 'recommended') {
-				$app1[$i]['internallabel'] = $l->t('Recommended');
+				$app1[$i]['internallabel'] = (string)$l->t('Recommended');
 				$app1[$i]['internalclass'] = 'recommendedapp';
 			}
 
diff --git a/lib/private/app/dependencyanalyzer.php b/lib/private/app/dependencyanalyzer.php
new file mode 100644
index 0000000000000000000000000000000000000000..fb4b376165632878d6afa967471ab0bba749b73c
--- /dev/null
+++ b/lib/private/app/dependencyanalyzer.php
@@ -0,0 +1,87 @@
+<?php
+ /**
+ * @author Thomas Müller
+ * @copyright 2014 Thomas Müller deepdiver@owncloud.com
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\App;
+
+class DependencyAnalyzer {
+
+	/** @var Platform */
+	private $system;
+
+	/** @var \OCP\IL10N */
+	private $l;
+
+	/** @var array  */
+	private $missing;
+
+	/** @var array  */
+	private $dependencies;
+
+	/**
+	 * @param array $app
+	 * @param Platform $platform
+	 * @param \OCP\IL10N $l
+	 */
+	function __construct(array $app, $platform, $l) {
+		$this->system = $platform;
+		$this->l = $l;
+		$this->missing = array();
+		$this->dependencies = array();
+		if (array_key_exists('dependencies', $app)) {
+			$this->dependencies = $app['dependencies'];
+		}
+	}
+
+	/**
+	 * @param array $app
+	 * @returns array of missing dependencies
+	 */
+	public function analyze() {
+		$this->analysePhpVersion();
+		$this->analyseSupportedDatabases();
+		return $this->missing;
+	}
+
+	private function analysePhpVersion() {
+		if (isset($this->dependencies['php']['@attributes']['min-version'])) {
+			$minVersion = $this->dependencies['php']['@attributes']['min-version'];
+			if (version_compare($this->system->getPhpVersion(), $minVersion, '<')) {
+				$this->missing[] = (string)$this->l->t('PHP %s or higher is required.', $minVersion);
+			}
+		}
+		if (isset($this->dependencies['php']['@attributes']['max-version'])) {
+			$maxVersion = $this->dependencies['php']['@attributes']['max-version'];
+			if (version_compare($this->system->getPhpVersion(), $maxVersion, '>')) {
+				$this->missing[] = (string)$this->l->t('PHP with a version less then %s is required.', $maxVersion);
+			}
+		}
+	}
+
+	private function analyseSupportedDatabases() {
+		if (!isset($this->dependencies['database'])) {
+			return;
+		}
+
+		$supportedDatabases = $this->dependencies['database'];
+		if (empty($supportedDatabases)) {
+			return;
+		}
+		$supportedDatabases = array_map(function($db) {
+			if (isset($db['@value'])) {
+				return $db['@value'];
+			}
+			return $db;
+		}, $supportedDatabases);
+		$currentDatabase = $this->system->getDatabase();
+		if (!in_array($currentDatabase, $supportedDatabases)) {
+			$this->missing[] = (string)$this->l->t('Following databases are supported: %s', join(', ', $supportedDatabases));
+		}
+	}
+}
diff --git a/lib/private/app/infoparser.php b/lib/private/app/infoparser.php
index b4bdbea5c04312fe358af607d0c39f14de9a728c..0bfbf6bd13977868f1d2262d032dc1868274cf91 100644
--- a/lib/private/app/infoparser.php
+++ b/lib/private/app/infoparser.php
@@ -47,7 +47,7 @@ class InfoParser {
 		if ($xml == false) {
 			return null;
 		}
-		$array = json_decode(json_encode((array)$xml), TRUE);
+		$array = $this->xmlToArray($xml, false);
 		if (is_null($array)) {
 			return null;
 		}
@@ -60,8 +60,11 @@ class InfoParser {
 		if (!array_key_exists('public', $array)) {
 			$array['public'] = array();
 		}
+		if (!array_key_exists('types', $array)) {
+			$array['types'] = array();
+		}
 
-		if (array_key_exists('documentation', $array)) {
+		if (array_key_exists('documentation', $array) && is_array($array['documentation'])) {
 			foreach ($array['documentation'] as $key => $url) {
 				// If it is not an absolute URL we assume it is a key
 				// i.e. admin-ldap will get converted to go.php?to=admin-ldap
@@ -73,9 +76,70 @@ class InfoParser {
 			}
 		}
 		if (array_key_exists('types', $array)) {
-			foreach ($array['types'] as $type => $v) {
-				unset($array['types'][$type]);
-				$array['types'][] = $type;
+			if (is_array($array['types'])) {
+				foreach ($array['types'] as $type => $v) {
+					unset($array['types'][$type]);
+					if (is_string($type)) {
+						$array['types'][] = $type;
+					}
+				}
+			} else {
+				$array['types'] = array();
+			}
+		}
+
+		return $array;
+	}
+
+	/**
+	 * @param \SimpleXMLElement $xml
+	 * @return array
+	 */
+	function xmlToArray($xml) {
+		if (!$xml->children()) {
+			return (string)$xml;
+		}
+
+		$array = array();
+		foreach ($xml->children() as $element => $node) {
+			$totalElement = count($xml->{$element});
+
+			if (!isset($array[$element])) {
+				$array[$element] = "";
+			}
+			/**
+			 * @var \SimpleXMLElement $node
+			 */
+
+			// Has attributes
+			if ($attributes = $node->attributes()) {
+				$data = array(
+					'@attributes' => array(),
+				);
+				if (!count($node->children())){
+					$value = (string)$node;
+					if (!empty($value)) {
+						$data['@value'] = (string)$node;
+					}
+				} else {
+					$data = array_merge($data, $this->xmlToArray($node));
+				}
+				foreach ($attributes as $attr => $value) {
+					$data['@attributes'][$attr] = (string)$value;
+				}
+
+				if ($totalElement > 1) {
+					$array[$element][] = $data;
+				} else {
+					$array[$element] = $data;
+				}
+				// Just a value
+			} else {
+				if ($totalElement > 1) {
+					$array[$element][] = $this->xmlToArray($node);
+				} else {
+					$array[$element] = $this->xmlToArray($node);
+				}
 			}
 		}
 
diff --git a/lib/private/app/platform.php b/lib/private/app/platform.php
new file mode 100644
index 0000000000000000000000000000000000000000..39f8a2979f9267cc3fd3e016378c6ebd64ff5329
--- /dev/null
+++ b/lib/private/app/platform.php
@@ -0,0 +1,33 @@
+<?php
+ /**
+ * @author Thomas Müller
+ * @copyright 2014 Thomas Müller deepdiver@owncloud.com
+ *
+ * This file is licensed under the Affero General Public License version 3 or
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace OC\App;
+
+use OCP\IConfig;
+
+class Platform {
+
+	function __construct(IConfig $config) {
+		$this->config = $config;
+	}
+
+	public function getPhpVersion() {
+		return phpversion();
+	}
+
+	public function getDatabase() {
+		$dbType = $this->config->getSystemValue('dbtype', 'sqlite');
+		if ($dbType === 'sqlite3') {
+			$dbType = 'sqlite';
+		}
+
+		return $dbType;
+	}
+}
diff --git a/settings/controller/appsettingscontroller.php b/settings/controller/appsettingscontroller.php
index 27205400affb4e657ed2c66e894359eb15fa8215..3ad52bd2187ee9577eea85125748e72fb99394bb 100644
--- a/settings/controller/appsettingscontroller.php
+++ b/settings/controller/appsettingscontroller.php
@@ -11,6 +11,8 @@
 
 namespace OC\Settings\Controller;
 
+use OC\App\DependencyAnalyzer;
+use OC\App\Platform;
 use \OCP\AppFramework\Controller;
 use OCP\IRequest;
 use OCP\IL10N;
@@ -123,10 +125,16 @@ class AppSettingsController extends Controller {
 			}
 			$app['groups'] = $groups;
 			$app['canUnInstall'] = !$app['active'] && $app['removable'];
+
+			// analyse dependencies
+			$dependencyAnalyzer = new DependencyAnalyzer($app, new Platform($this->config), $this->l10n);
+			$missing = $dependencyAnalyzer->analyze();
+
+			$app['canInstall'] = empty($missing);
+			$app['missingDependencies'] = $missing;
 			return $app;
 		}, $apps);
 
 		return array('apps' => $apps, 'status' => 'success');
 	}
-
 }
diff --git a/settings/css/settings.css b/settings/css/settings.css
index c18d5913b6f6d2d94490252111b8a1890de32381..4594a22c6d01c52fbd06b28a6eb3361b6e66fd1a 100644
--- a/settings/css/settings.css
+++ b/settings/css/settings.css
@@ -200,6 +200,12 @@ span.version { margin-left:1em; margin-right:1em; color:#555; }
 	border-bottom: 1px solid #e8e8e8;
 }
 
+.missing-dependencies {
+	list-style: initial;
+	list-style-type: initial;
+	list-style-position: inside;
+}
+
 /* Transition to complete width! */
 .app:hover, .app:active { max-width: inherit; }
 
diff --git a/settings/templates/apps.php b/settings/templates/apps.php
index 1ad37000f3973083a4b8273b4e108b48dd45ca56..3bb0d45f582ee4a017b57cb62bbc47a1b7dc8d4b 100644
--- a/settings/templates/apps.php
+++ b/settings/templates/apps.php
@@ -51,6 +51,15 @@
 		{{/if}}
 	</p>
 	{{/if}}
+	{{#unless canInstall}}
+	<div><?php p($l->t('This app cannot be installed because the following dependencies are not fulfilled:')); ?></div>
+	<ul class="missing-dependencies">
+	{{#each missingDependencies}}
+	<li>{{this}}</li>
+	{{/each}}
+	</ul>
+	{{/unless}}
+
 	{{#if update}}
 	<input class="update" type="submit" value="<?php p($l->t('Update to %s', array('{{update}}'))); ?>" data-appid="{{id}}" />
 	{{/if}}
@@ -61,8 +70,10 @@
 	<br />
 	<input type="hidden" id="group_select" title="<?php p($l->t('All')); ?>" style="width: 200px">
 	{{else}}
+	{{#if canInstall}}
 	<input class="enable" type="submit" data-appid="{{id}}" data-active="false" value="<?php p($l->t("Enable"));?>"/>
 	{{/if}}
+	{{/if}}
 	{{#if canUnInstall}}
 	<input class="uninstall" type="submit" value="<?php p($l->t('Uninstall App')); ?>" data-appid="{{id}}" />
 	{{/if}}
diff --git a/tests/data/app/expected-info.json b/tests/data/app/expected-info.json
index c67d6d657d224b2839cc3002082ba87568edf7f0..fc0ab22497705b7d132af766f1b6ab112e2b14da 100644
--- a/tests/data/app/expected-info.json
+++ b/tests/data/app/expected-info.json
@@ -15,5 +15,35 @@
 	},
 	"rememberlogin": "false",
 	"types": ["filesystem"],
-	"ocsid": "166047"
+	"ocsid": "166047",
+	"dependencies": {
+		"php": {
+			"@attributes" : {
+				"min-version": "5.4",
+				"max-version": "5.5"
+			}
+		},
+		"database": [
+			{
+				"@attributes" : {
+					"min-version": "3.0"
+				},
+				"@value": "sqlite"},
+			"mysql"
+		],
+		"command": [
+			{
+				"@attributes" : {
+					"os": "linux"
+				},
+				"@value": "grep"
+			},
+			{
+				"@attributes" : {
+					"os": "windows"
+				},
+				"@value": "notepad.exe"
+			}
+		]
+	}
 }
diff --git a/tests/data/app/valid-info.xml b/tests/data/app/valid-info.xml
index 6fcef693bede812dfb00ca77f6361a6d7bb7efae..f01f5fd55eaad585b60b8930b64e6bbaf5b1292f 100644
--- a/tests/data/app/valid-info.xml
+++ b/tests/data/app/valid-info.xml
@@ -19,4 +19,11 @@
 		<filesystem/>
 	</types>
 	<ocsid>166047</ocsid>
+	<dependencies>
+		<php min-version="5.4" max-version="5.5"/>
+		<database min-version="3.0">sqlite</database>
+		<database>mysql</database>
+		<command os="linux">grep</command>
+		<command os="windows">notepad.exe</command>
+	</dependencies>
 </info>
diff --git a/tests/lib/app/dependencyanalyzer.php b/tests/lib/app/dependencyanalyzer.php
new file mode 100644
index 0000000000000000000000000000000000000000..7d06842e8ad039fce12355ac686c652ecd9e60e2
--- /dev/null
+++ b/tests/lib/app/dependencyanalyzer.php
@@ -0,0 +1,109 @@
+<?php
+
+/**
+ * @author Thomas Müller
+ * @copyright 2014 Thomas Müller deepdiver@owncloud.com
+ * later.
+ * See the COPYING-README file.
+ */
+
+namespace Test\App;
+
+use OC;
+use OC\App\Platform;
+use OCP\IL10N;
+
+class DependencyAnalyzer extends \PHPUnit_Framework_TestCase {
+
+	/**
+	 * @var Platform
+	 */
+	private $platformMock;
+
+	/**
+	 * @var IL10N
+	 */
+	private $l10nMock;
+
+	public function setUp() {
+		$this->platformMock = $this->getMockBuilder('\OC\App\Platform')
+			->disableOriginalConstructor()
+			->getMock();
+		$this->platformMock->expects($this->any())
+			->method('getPhpVersion')
+			->will( $this->returnValue('5.4.3'));
+		$this->platformMock->expects($this->any())
+			->method('getDatabase')
+			->will( $this->returnValue('mysql'));
+		$this->l10nMock = $this->getMockBuilder('\OCP\IL10N')
+			->disableOriginalConstructor()
+			->getMock();
+		$this->l10nMock->expects($this->any())
+			->method('t')
+			->will($this->returnCallback(function($text, $parameters = array()) {
+				return vsprintf($text, $parameters);
+			}));
+	}
+
+	/**
+	 * @dataProvider providesPhpVersion
+	 */
+	public function testPhpVersion($expectedMissing, $minVersion, $maxVersion) {
+		$app = array(
+			'dependencies' => array(
+				'php' => array()
+			)
+		);
+		if (!is_null($minVersion)) {
+			$app['dependencies']['php']['@attributes']['min-version'] = $minVersion;
+		}
+		if (!is_null($maxVersion)) {
+			$app['dependencies']['php']['@attributes']['max-version'] = $maxVersion;
+		}
+		$analyser = new \OC\App\DependencyAnalyzer($app, $this->platformMock, $this->l10nMock);
+		$missing = $analyser->analyze();
+
+		$this->assertTrue(is_array($missing));
+		$this->assertEquals(count($expectedMissing), count($missing));
+		$this->assertEquals($expectedMissing, $missing);
+	}
+
+	/**
+	 * @dataProvider providesDatabases
+	 */
+	public function testDatabases($expectedMissing, $databases) {
+		$app = array(
+			'dependencies' => array(
+			)
+		);
+		if (!is_null($databases)) {
+			$app['dependencies']['database'] = $databases;
+		}
+		$analyser = new \OC\App\DependencyAnalyzer($app, $this->platformMock, $this->l10nMock);
+		$missing = $analyser->analyze();
+
+		$this->assertTrue(is_array($missing));
+		$this->assertEquals(count($expectedMissing), count($missing));
+		$this->assertEquals($expectedMissing, $missing);
+	}
+
+	function providesDatabases() {
+		return array(
+			// non BC - in case on databases are defined -> all are supported
+			array(array(), null),
+			array(array(), array()),
+			array(array('Following databases are supported: sqlite, postgres'), array('sqlite', array('@value' => 'postgres'))),
+		);
+	}
+
+	function providesPhpVersion() {
+		return array(
+			array(array(), null, null),
+			array(array(), '5.4', null),
+			array(array(), null, '5.5'),
+			array(array(), '5.4', '5.5'),
+			array(array('PHP 5.4.4 or higher is required.'), '5.4.4', null),
+			array(array('PHP with a version less then 5.4.2 is required.'), null, '5.4.2'),
+		);
+	}
+}
diff --git a/tests/lib/app/infoparser.php b/tests/lib/app/infoparser.php
index 277e1582e45c19f93ba717c8840ce71db82a7ffb..13c0b51e117e212e9543bf39a6f42787ca00bf2b 100644
--- a/tests/lib/app/infoparser.php
+++ b/tests/lib/app/infoparser.php
@@ -39,15 +39,23 @@ class InfoParser extends \PHPUnit_Framework_TestCase {
 		$this->parser = new \OC\App\InfoParser($httpHelper, $urlGenerator);
 	}
 
-	public function testParsingValidXml() {
-		$expectedData = json_decode(file_get_contents(OC::$SERVERROOT.'/tests/data/app/expected-info.json'), true);
-		$data = $this->parser->parse(OC::$SERVERROOT.'/tests/data/app/valid-info.xml');
+	/**
+	 * @dataProvider providesInfoXml
+	 */
+	public function testParsingValidXml($expectedJson, $xmlFile) {
+		$expectedData = null;
+		if (!is_null($expectedJson)) {
+			$expectedData = json_decode(file_get_contents(OC::$SERVERROOT . "/tests/data/app/$expectedJson"), true);
+		}
+		$data = $this->parser->parse(OC::$SERVERROOT. "/tests/data/app/$xmlFile");
 
 		$this->assertEquals($expectedData, $data);
 	}
 
-	public function testParsingInvalidXml() {
-		$data = $this->parser->parse(OC::$SERVERROOT.'/tests/data/app/invalid-info.xml');
-		$this->assertNull($data);
+	function providesInfoXml() {
+		return array(
+			array('expected-info.json', 'valid-info.xml'),
+			array(null, 'invalid-info.xml'),
+		);
 	}
 }