summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Marien Fressinaud <dev@marienfressinaud.fr> 2014-10-20 11:54:31 +0200
committerGravatar Marien Fressinaud <dev@marienfressinaud.fr> 2014-10-20 11:54:31 +0200
commit7080a32650ab8b19e917d8add944a75cc98381bc (patch)
treea06593be4c12fcb21566c0d249af3ee63d8429df
parent3bad4d138e5c4a86aa3f88dea3787c3335861ce4 (diff)
Add checking installation feature
-rw-r--r--app/Controllers/updateController.php14
-rw-r--r--app/Models/DatabaseDAO.php83
-rw-r--r--app/Models/DatabaseDAOSQLite.php48
-rw-r--r--app/Models/Factory.php9
-rw-r--r--app/SQL/install.sql.mysql.php2
-rw-r--r--app/SQL/install.sql.sqlite.php2
-rw-r--r--app/layout/aside_configure.phtml7
-rw-r--r--app/layout/header.phtml1
-rw-r--r--app/views/update/checkInstall.phtml30
-rw-r--r--lib/lib_rss.php62
10 files changed, 252 insertions, 6 deletions
diff --git a/app/Controllers/updateController.php b/app/Controllers/updateController.php
index 9d1e1ddf5..4ebb11f51 100644
--- a/app/Controllers/updateController.php
+++ b/app/Controllers/updateController.php
@@ -12,7 +12,6 @@ class FreshRSS_update_Controller extends Minz_ActionController {
invalidateHttpCache();
- Minz_View::prependTitle(_t('update_system') . ' · ');
$this->view->update_to_apply = false;
$this->view->last_update_time = 'unknown';
$this->view->check_last_hour = false;
@@ -24,6 +23,8 @@ class FreshRSS_update_Controller extends Minz_ActionController {
}
public function indexAction() {
+ Minz_View::prependTitle(_t('update_system') . ' · ');
+
if (file_exists(UPDATE_FILENAME) && !is_writable(FRESHRSS_PATH)) {
$this->view->message = array(
'status' => 'bad',
@@ -126,4 +127,15 @@ class FreshRSS_update_Controller extends Minz_ActionController {
}
}
}
+
+ /**
+ * This action displays information about installation.
+ */
+ public function checkInstallAction() {
+ Minz_View::prependTitle(_t('gen.title.check_install') . ' · ');
+
+ $this->view->status_php = check_install_php();
+ $this->view->status_files = check_install_files();
+ $this->view->status_database = check_install_database();
+ }
}
diff --git a/app/Models/DatabaseDAO.php b/app/Models/DatabaseDAO.php
new file mode 100644
index 000000000..0d85718e3
--- /dev/null
+++ b/app/Models/DatabaseDAO.php
@@ -0,0 +1,83 @@
+<?php
+
+/**
+ * This class is used to test database is well-constructed.
+ */
+class FreshRSS_DatabaseDAO extends Minz_ModelPdo {
+ public function tablesAreCorrect() {
+ $sql = 'SHOW TABLES';
+ $stm = $this->bd->prepare($sql);
+ $stm->execute();
+ $res = $stm->fetchAll(PDO::FETCH_ASSOC);
+
+ $tables = array(
+ $this->prefix . 'category' => false,
+ $this->prefix . 'feed' => false,
+ $this->prefix . 'entry' => false,
+ );
+ foreach ($res as $value) {
+ $tables[array_pop($value)] = true;
+ }
+
+ return count(array_keys($tables, true, true)) == count($tables);
+ }
+
+ public function getSchema($table) {
+ $sql = 'DESC ' . $this->prefix . $table;
+ $stm = $this->bd->prepare($sql);
+ $stm->execute();
+
+ return $this->listDaoToSchema($stm->fetchAll(PDO::FETCH_ASSOC));
+ }
+
+ public function checkTable($table, $schema) {
+ $columns = $this->getSchema($table);
+
+ $ok = (count($columns) == count($schema));
+ foreach ($columns as $c) {
+ $ok &= in_array($c['name'], $schema);
+ }
+
+ return $ok;
+ }
+
+ public function categoryIsCorrect() {
+ return $this->checkTable('category', array(
+ 'id', 'name'
+ ));
+ }
+
+ public function feedIsCorrect() {
+ return $this->checkTable('feed', array(
+ 'id', 'url', 'category', 'name', 'website', 'description', 'lastUpdate',
+ 'priority', 'pathEntries', 'httpAuth', 'error', 'keep_history', 'ttl',
+ 'cache_nbEntries', 'cache_nbUnreads'
+ ));
+ }
+
+ public function entryIsCorrect() {
+ return $this->checkTable('entry', array(
+ 'id', 'guid', 'title', 'author', 'content_bin', 'link', 'date', 'is_read',
+ 'is_favorite', 'id_feed', 'tags'
+ ));
+ }
+
+ public function daoToSchema($dao) {
+ return array(
+ 'name' => $dao['Field'],
+ 'type' => strtolower($dao['Type']),
+ 'notnull' => (bool)$dao['Null'],
+ 'default' => $dao['Default'],
+ );
+ }
+
+ public function listDaoToSchema($listDAO) {
+ $list = array();
+
+ foreach ($listDAO as $dao) {
+ $list[] = $this->daoToSchema($dao);
+ }
+
+ return $list;
+ }
+}
diff --git a/app/Models/DatabaseDAOSQLite.php b/app/Models/DatabaseDAOSQLite.php
new file mode 100644
index 000000000..7f53f967d
--- /dev/null
+++ b/app/Models/DatabaseDAOSQLite.php
@@ -0,0 +1,48 @@
+<?php
+
+/**
+ * This class is used to test database is well-constructed (SQLite).
+ */
+class FreshRSS_DatabaseDAOSQLite extends FreshRSS_DatabaseDAO {
+ public function tablesAreCorrect() {
+ $sql = 'SELECT name FROM sqlite_master WHERE type="table"';
+ $stm = $this->bd->prepare($sql);
+ $stm->execute();
+ $res = $stm->fetchAll(PDO::FETCH_ASSOC);
+
+ $tables = array(
+ 'category' => false,
+ 'feed' => false,
+ 'entry' => false,
+ );
+ foreach ($res as $value) {
+ $tables[$value['name']] = true;
+ }
+
+ return count(array_keys($tables, true, true)) == count($tables);
+ }
+
+ public function getSchema($table) {
+ $sql = 'PRAGMA table_info(' . $table . ')';
+ $stm = $this->bd->prepare($sql);
+ $stm->execute();
+
+ return $this->listDaoToSchema($stm->fetchAll(PDO::FETCH_ASSOC));
+ }
+
+ public function entryIsCorrect() {
+ return $this->checkTable('entry', array(
+ 'id', 'guid', 'title', 'author', 'content', 'link', 'date', 'is_read',
+ 'is_favorite', 'id_feed', 'tags'
+ ));
+ }
+
+ public function daoToSchema($dao) {
+ return array(
+ 'name' => $dao['name'],
+ 'type' => strtolower($dao['type']),
+ 'notnull' => $dao['notnull'] === '1' ? true : false,
+ 'default' => $dao['dflt_value'],
+ );
+ }
+}
diff --git a/app/Models/Factory.php b/app/Models/Factory.php
index 93f4552f7..91cb84998 100644
--- a/app/Models/Factory.php
+++ b/app/Models/Factory.php
@@ -29,4 +29,13 @@ class FreshRSS_Factory {
}
}
+ public static function createDatabaseDAO($username = null) {
+ $db = Minz_Configuration::dataBase();
+ if ($db['type'] === 'sqlite') {
+ return new FreshRSS_DatabaseDAOSQLite($username);
+ } else {
+ return new FreshRSS_DatabaseDAO($username);
+ }
+ }
+
}
diff --git a/app/SQL/install.sql.mysql.php b/app/SQL/install.sql.mysql.php
index 16cb3a3b8..cf0159199 100644
--- a/app/SQL/install.sql.mysql.php
+++ b/app/SQL/install.sql.mysql.php
@@ -57,5 +57,3 @@ INSERT IGNORE INTO `%1$scategory` (id, name) VALUES(1, "%2$s");
');
define('SQL_DROP_TABLES', 'DROP TABLES %1$sentry, %1$sfeed, %1$scategory');
-
-define('SQL_SHOW_TABLES', 'SHOW tables;');
diff --git a/app/SQL/install.sql.sqlite.php b/app/SQL/install.sql.sqlite.php
index 7988ada04..30bca2810 100644
--- a/app/SQL/install.sql.sqlite.php
+++ b/app/SQL/install.sql.sqlite.php
@@ -55,5 +55,3 @@ $SQL_CREATE_TABLES = array(
);
define('SQL_DROP_TABLES', 'DROP TABLES %1$sentry, %1$sfeed, %1$scategory');
-
-define('SQL_SHOW_TABLES', 'SELECT name FROM sqlite_master WHERE type="table"');
diff --git a/app/layout/aside_configure.phtml b/app/layout/aside_configure.phtml
index 20446c877..32dc19a4e 100644
--- a/app/layout/aside_configure.phtml
+++ b/app/layout/aside_configure.phtml
@@ -31,7 +31,12 @@
<li class="item<?php echo Minz_Request::controllerName() === 'auth' ? ' active' : ''; ?>">
<a href="<?php echo _url('auth', 'index'); ?>"><?php echo _t('gen.menu.authentication'); ?></a>
</li>
- <li class="item<?php echo Minz_Request::controllerName() === 'update' ? ' active' : ''; ?>">
+ <li class="item<?php echo Minz_Request::controllerName() === 'update' &&
+ Minz_Request::actionName() === 'checkInstall' ? ' active' : ''; ?>">
+ <a href="<?php echo _url('update', 'checkInstall'); ?>"><?php echo _t('gen.menu.check_install'); ?></a>
+ </li>
+ <li class="item<?php echo Minz_Request::controllerName() === 'update' &&
+ Minz_Request::actionName() === 'index' ? ' active' : ''; ?>">
<a href="<?php echo _url('update', 'index'); ?>"><?php echo _t('update'); ?></a>
</li>
<?php } ?>
diff --git a/app/layout/header.phtml b/app/layout/header.phtml
index e848ac4eb..506cec175 100644
--- a/app/layout/header.phtml
+++ b/app/layout/header.phtml
@@ -68,6 +68,7 @@ if (Minz_Configuration::canLogIn()) {
<li class="dropdown-header"><?php echo _t('gen.menu.admin'); ?></li>
<li class="item"><a href="<?php echo _url('user', 'manage'); ?>"><?php echo _t('gen.menu.manage_users'); ?></a></li>
<li class="item"><a href="<?php echo _url('auth', 'index'); ?>"><?php echo _t('gen.menu.authentication'); ?></a></li>
+ <li class="item"><a href="<?php echo _url('update', 'checkInstall'); ?>"><?php echo _t('gen.menu.check_install'); ?></a></li>
<li class="item"><a href="<?php echo _url('update', 'index'); ?>"><?php echo _t('update'); ?></a></li>
<?php } ?>
<li class="separator"></li>
diff --git a/app/views/update/checkInstall.phtml b/app/views/update/checkInstall.phtml
new file mode 100644
index 000000000..32058714e
--- /dev/null
+++ b/app/views/update/checkInstall.phtml
@@ -0,0 +1,30 @@
+<?php $this->partial('aside_configure'); ?>
+
+<div class="post">
+ <a href="<?php echo _url('index', 'index'); ?>"><?php echo _t('back_to_rss_feeds'); ?></a>
+
+ <h2><?php echo _t('admin.check_install.php'); ?></h2>
+
+ <?php foreach ($this->status_php as $key => $status) { ?>
+ <p class="alert <?php echo $status ? 'alert-success' : 'alert-error'; ?>">
+ <?php echo _t('admin.check_install.' . $key . '.' . ($status ? 'ok' : 'nok')); ?>
+ </p>
+ <?php } ?>
+
+ <h2><?php echo _t('admin.check_install.files'); ?></h2>
+
+ <?php foreach ($this->status_files as $key => $status) { ?>
+ <p class="alert <?php echo $status ? 'alert-success' : 'alert-error'; ?>">
+ <?php echo _t('admin.check_install.' . $key . '.' . ($status ? 'ok' : 'nok')); ?>
+ </p>
+ <?php } ?>
+
+ <h2><?php echo _t('admin.check_install.database'); ?></h2>
+
+ <?php foreach ($this->status_database as $key => $status) { ?>
+ <p class="alert <?php echo $status ? 'alert-success' : 'alert-error'; ?>">
+ <?php echo _t('admin.check_install.' . $key . '.' . ($status ? 'ok' : 'nok')); ?>
+ </p>
+ <?php } ?>
+
+</div>
diff --git a/lib/lib_rss.php b/lib/lib_rss.php
index 2f9a2ea45..dbed207d0 100644
--- a/lib/lib_rss.php
+++ b/lib/lib_rss.php
@@ -245,3 +245,65 @@ function is_referer_from_same_domain() {
}
return (isset($host['port']) ? $host['port'] : 0) === (isset($referer['port']) ? $referer['port'] : 0);
}
+
+
+/**
+ *
+ */
+function check_install_php() {
+ return array(
+ 'php' => version_compare(PHP_VERSION, '5.2.1') >= 0,
+ 'minz' => file_exists(LIB_PATH . '/Minz'),
+ 'curl' => extension_loaded('curl'),
+ 'pdo_mysql' => extension_loaded('pdo_mysql'),
+ 'pdo_sqlite' => extension_loaded('pdo_sqlite'),
+ 'pdo' => extension_loaded('pdo_mysql') || extension_loaded('pdo_sqlite'),
+ 'pcre' => extension_loaded('pcre'),
+ 'ctype' => extension_loaded('ctype'),
+ 'dom' => class_exists('DOMDocument'),
+ 'json' => extension_loaded('json'),
+ 'zip' => extension_loaded('zip'),
+ );
+}
+
+
+/**
+ *
+ */
+function check_install_files() {
+ return array(
+ 'data' => DATA_PATH && is_writable(DATA_PATH),
+ 'cache' => CACHE_PATH && is_writable(CACHE_PATH),
+ 'logs' => LOG_PATH && is_writable(LOG_PATH),
+ 'favicons' => is_writable(DATA_PATH . '/favicons'),
+ 'persona' => is_writable(DATA_PATH . '/persona'),
+ 'tokens' => is_writable(DATA_PATH . '/tokens'),
+ );
+}
+
+
+/**
+ *
+ */
+function check_install_database() {
+ $status = array(
+ 'connection' => true,
+ 'tables' => false,
+ 'categories' => false,
+ 'feeds' => false,
+ 'entries' => false,
+ );
+
+ try {
+ $dbDAO = FreshRSS_Factory::createDatabaseDAO();
+
+ $status['tables'] = $dbDAO->tablesAreCorrect();
+ $status['categories'] = $dbDAO->categoryIsCorrect();
+ $status['feeds'] = $dbDAO->feedIsCorrect();
+ $status['entries'] = $dbDAO->entryIsCorrect();
+ } catch(Minz_PDOConnectionException $e) {
+ $status['connection'] = false;
+ }
+
+ return $status;
+}