summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--app/class/database.class.php51
-rw-r--r--app/class/form.class.php179
-rw-r--r--app/class/globals.php22
-rw-r--r--app/model/dbconfig.php42
-rw-r--r--app/view/dbconfig.php90
-rw-r--r--app/view/formctrl.php39
-rw-r--r--app/view/stdpage.php7
7 files changed, 427 insertions, 3 deletions
diff --git a/app/class/database.class.php b/app/class/database.class.php
index cdfdfce..3d94e16 100644
--- a/app/class/database.class.php
+++ b/app/class/database.class.php
@@ -115,6 +115,57 @@ abstract class database
return true;
}
+
+ /*
+ * Test and set new database configuration parameters.
+ * If the given params fail, error's are set and this
+ * function returns false. On success, parameters are
+ * written to 'dbconfig.php' and true is returned.
+ */
+ public static function setConfig(string $engine, string $host,
+ string $uname, string $passwd, string $name) : bool
+ {
+ global $_SCROTT;
+
+ /* test configuration */
+ $_SCROTT['conf'] = "conf";
+ $_SCROTT['dbEngine'] = $engine;
+ $_SCROTT['dbHost'] = $host;
+ $_SCROTT['dbUname'] = $uname;
+ $_SCROTT['dbPasswd'] = $passwd;
+ $_SCROTT['dbName'] = $name;
+
+ try
+ {
+ $db = self::getInstance();
+ }
+ catch (Exception $e)
+ {
+ logError(ERROR, $e->getMessage());
+ return false;
+ }
+
+ /* write file */
+ $f = fopen(DATABASE_CONFIG_FILE, "w");
+
+ if (!$f)
+ {
+ logError(ERROR, "Can not create configuration file");
+ return false;
+ }
+
+ fwrite($f, "<?php\n");
+ fwrite($f, "\$_SCROTT['conf'] = 'conf';\n");
+ fwrite($f, "\$_SCROTT['dbEngine'] = '" . $engine . "';\n");
+ fwrite($f, "\$_SCROTT['dbHost'] = '" . $host . "';\n");
+ fwrite($f, "\$_SCROTT['dbUname'] = '" . $uname . "';\n");
+ fwrite($f, "\$_SCROTT['dbPasswd'] = '" . $passwd . "';\n");
+ fwrite($f, "\$_SCROTT['dbName'] = '" . $name . "';\n");
+ fwrite($f, "?>\n");
+
+ fclose($f);
+ return true;
+ }
}
?>
diff --git a/app/class/form.class.php b/app/class/form.class.php
new file mode 100644
index 0000000..8f9d936
--- /dev/null
+++ b/app/class/form.class.php
@@ -0,0 +1,179 @@
+<?php
+
+/*
+ * SCROTT IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to UNLICENSE
+ */
+
+/*
+ * Model web-forms and simplify the process of accepting, validating, and
+ * sanitizing user input.
+ */
+class form
+{
+ /*
+ * These arrays track the meta-data of all fields defined on this
+ * form. This mainly includes their type, range (if numeric), and
+ * whether or not the field is required.
+ */
+ private $textFields = array();
+ private $numbFields = array();
+ private $enumFields = array();
+
+ /*
+ * Add new text field to this form
+ */
+ public function text(string $name, bool $required = true,
+ string $deflt = "") : void
+ {
+ $this->textFields[] = array(
+ 'name' => $name,
+ 'required' => $required,
+ 'default' => $deflt,
+ );
+ }
+
+ /*
+ * Add new numeric field to this form
+ */
+ public function numeric(string $name, ?int $min = NULL, ?int $max = NULL,
+ int $deflt = 0, bool $isInt = true, bool $required = true) : void
+ {
+ $this->numbFields[] = array(
+ 'name' => $name,
+ 'min' => $min,
+ 'max' => $max,
+ 'default' => $deflt,
+ 'isInt' => $isInt,
+ 'required' => $required,
+ );
+ }
+
+ /*
+ * Add new enumeration field to this form
+ */
+ public function enum(string $name, array $values, $deflt = NULL,
+ bool $required = true) : void
+ {
+ $this->enumFields[] = array(
+ 'name' => $name,
+ 'values' => $values,
+ 'default' => $deflt,
+ 'required' => $required,
+ );
+ }
+
+ /*
+ * Add new boolean field to this form
+ */
+ public function flag(string $name) : void
+ {
+ $this->enum($name, array("1", "0"), "0", false);
+ }
+
+ /*
+ * Populate this form with input data from web page. If an error
+ * is encountered, or a required field is missing, false is returned.
+ */
+ public function populate(array $input) : bool
+ {
+ /* detect duplicate names */
+ $names = array();
+
+ foreach ($this->textFields as $field)
+ $names[] = $field['name'];
+
+ foreach ($this->numbFields as $field)
+ $names[] = $field['name'];
+
+ foreach ($this->enumFields as $field)
+ $names[] = $field['name'];
+
+ if (count(array_unique($names)) != count($names))
+ throw new Exception("Internal error: Duplicate field names defined in form");
+
+ /* init text fields */
+ foreach ($this->textFields as $field)
+ {
+ if (isset($input[$field['name']]) && $input[$field['name']] != "")
+ $this->{$field['name']} = htmlentities($input[$field['name']], ENT_QUOTES);
+
+ else if ($field['required'])
+ logError(ERROR, $field['name'] . " is required");
+
+ else
+ $this->{$field['name']} = $field['default'];
+ }
+
+ /* init numeric fields */
+ foreach ($this->numbFields as $field)
+ {
+ if (isset($input[$field['name']]) && $input[$field['name']] != "")
+ {
+ if (!is_numeric($input[$field['name']]))
+ {
+ logError(ERROR, $field['name'] . " must be numeric");
+ continue;
+ }
+
+ if ($field['isInt'] && (floor($input[$field['name']]) != $input[$field['name']]))
+ {
+ logError(ERROR, $field['name'] . " must be an integer");
+ continue;
+ }
+
+ if (!is_null($field['min']) && ($input[$field['name']] < $field['min']))
+ {
+ logError(ERROR, $field['name'] . " must be no less than " . $field['min']);
+ continue;
+ }
+
+ if (!is_null($field['max']) && ($input[$field['name']] > $field['max']))
+ {
+ logError(ERROR, $field['name'] . " must be no more than " . $field['max']);
+ continue;
+ }
+
+ $this->{$field['name']} = $input[$field['name']];
+ }
+
+ else if ($field['required'])
+ logError(ERROR, $field['name'] . " is required");
+
+ else
+ $this->{$field['name']} = $field['default'];
+ }
+
+ /* init enum fields */
+ foreach ($this->enumFields as $field)
+ {
+ if (isset($input[$field['name']]) && $input[$field['name']] != "")
+ {
+ if (array_search($input[$field['name']], $field['values']) === false)
+ {
+ logError(ERROR, $field['name'] . " is not an appropriate value");
+ continue;
+ }
+
+ $this->{$field['name']} = $input[$field['name']];
+ }
+
+ else if ($field['required'])
+ logError(ERROR, $field['name'] . " is required");
+
+ else
+ $this->{$field['name']} = $field['default'];
+ }
+
+ return !isError(ERROR);
+ }
+}
+
+?>
diff --git a/app/class/globals.php b/app/class/globals.php
index 615efa6..776fc35 100644
--- a/app/class/globals.php
+++ b/app/class/globals.php
@@ -77,6 +77,28 @@ function require_https() : void
}
/*
+ * Check whether an action string was submitted by the user agent
+ */
+function isAction(string $action) : bool
+{
+ if (!isset($_REQUEST['action']))
+ return false;
+
+ return $_REQUEST['action'] == $action;
+}
+
+/*
+ * Get an array of submitted form input
+ */
+function input() : array
+{
+ if (!isset($_REQUEST['input']))
+ throw new Exception("Requested form input, but no input data was supplied");
+
+ return $_REQUEST['input'];
+}
+
+/*
* Check for errors, warnings, or notices
*/
function isError(string $level) : bool
diff --git a/app/model/dbconfig.php b/app/model/dbconfig.php
new file mode 100644
index 0000000..c66b052
--- /dev/null
+++ b/app/model/dbconfig.php
@@ -0,0 +1,42 @@
+<?php
+
+/*
+ * SCROTT IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to UNLICENSE
+ */
+
+require_once "class/database.class.php";
+require_once "class/form.class.php";
+
+/*
+ * Action: save - Write given configuration parameters to the database
+ * configuration file.
+ */
+if (isAction("save"))
+{
+ $form = new form();
+ $form->text("dbHost");
+ $form->text("dbUname");
+ $form->text("dbPasswd", false);
+ $form->text("dbName");
+
+ if (!$form->populate(input()))
+ return;
+
+ $stat = database::setConfig("mysql", $form->dbHost, $form->dbUname,
+ $form->dbPasswd, $form->dbName);
+
+ if (!$stat)
+ return;
+
+ location("/");
+}
+
+?>
diff --git a/app/view/dbconfig.php b/app/view/dbconfig.php
new file mode 100644
index 0000000..006c28e
--- /dev/null
+++ b/app/view/dbconfig.php
@@ -0,0 +1,90 @@
+<?php
+
+/*
+ * SCROTT IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to UNLICENSE
+ */
+
+require_once "model/dbconfig.php";
+require_once "view/stdpage.php";
+require_once "view/formctrl.php";
+
+?>
+
+<!DOCTYPE html>
+
+<html lang="en">
+ <head>
+ <?=stdpage\head( "Database Configuration" )?>
+
+ <style type="text/css">
+ body { padding-top: 50px; }
+ </style>
+ </head>
+
+ <body>
+ <?=stdpage\top()?>
+
+ <div class="container">
+ <div class="jumbotron">
+ <h2 class="text-center">
+ <span class="glyphicon glyphicon-user"></span>&nbsp;&nbsp;&nbsp;
+ <span class="glyphicon glyphicon-th"></span>&nbsp;&nbsp;&nbsp;
+ <span class="glyphicon glyphicon-edit"></span>&nbsp;&nbsp;&nbsp;
+ <span class="glyphicon glyphicon-tasks"></span>&nbsp;&nbsp;&nbsp;
+ <span class="glyphicon glyphicon-inbox"></span>&nbsp;&nbsp;&nbsp;
+ <span class="glyphicon glyphicon-envelope"></span>&nbsp;&nbsp;&nbsp;
+ </h2>
+
+ <h1 class="text-center">Welcome to Scrott!</h1>
+ <hr />
+
+ <p class="text-center">You're seeing this page because the file "dbconfig.php" is missing.</p>
+ <p class="text-center">Please fill out the form below to configure Scrott to use your database.</p>
+ <hr />
+
+ <p class="text-center">This form will save your database parameters to the configuration file.<br />
+ Scrott needs this information before it can begin working!</p>
+
+ <h5 class="text-center">
+ It is presumed that you are the administrator for this Scrott install.<br />
+ There is a security risk involved with exposing this page to the public!
+ </h5>
+
+ <div class="row">
+ <div class="col-md-2"></div>
+
+ <div class="col-md-8">
+ <div class="panel panel-default">
+ <div class="panel-body">
+ <form method="post" action="<?=ap()?>">
+ <?=formctrl\formname( "save" )?>
+ <?=formctrl\text( "Engine", "dbEngine", "MySQL", "", false, true )?>
+ <?=formctrl\text( "Hostname", "dbHost", "", "localhost" )?>
+ <?=formctrl\text( "Username", "dbUname", "", "root" )?>
+ <?=formctrl\password( "Password", "dbPasswd", false )?>
+ <?=formctrl\text( "Database Name", "dbName", "", "db_scrott" )?>
+
+ <button type="submit" class="btn btn-primary pull-right">
+ Use these settings
+ </button>
+ </form>
+ </div>
+ </div>
+ </div>
+
+ <div class="col-md-2"></div>
+ </div>
+ </div>
+ </div>
+
+ <?=stdpage\foot()?>
+ </body>
+</html>
diff --git a/app/view/formctrl.php b/app/view/formctrl.php
new file mode 100644
index 0000000..3683eb4
--- /dev/null
+++ b/app/view/formctrl.php
@@ -0,0 +1,39 @@
+<?php
+
+/*
+ * SCROTT IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
+ * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
+ * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ *
+ * For more information, please refer to UNLICENSE
+ */
+
+namespace formctrl;
+
+?>
+<?php function formname(string $name) : void { ?>
+
+ <input type="hidden" name="action" value="<?=$name?>" />
+
+<?php } ?>
+<?php function text(string $label, string $name, string $value = "", string $placeholder = "",
+ bool $required = true, bool $disabled = false) : void { ?>
+
+ <div class="form-group">
+ <label><?=$label?></label>
+ <input type="text" name="input[<?=$name?>]" value="<?=$value?>" placeholder="<?=$placeholder?>" class="form-control" <?=($required ? "required" : "")?> <?=($disabled ? "disabled" : "")?> />
+ </div>
+
+<?php } ?>
+<?php function password(string $label, string $name, bool $required = true) : void {?>
+
+ <div class="form-group">
+ <label><?=$label?></label>
+ <input type="password" name="input[<?=$name?>]" class="form-control" <?=($required ? "required" : "")?> />
+ </div>
+
+<?php } ?>
diff --git a/app/view/stdpage.php b/app/view/stdpage.php
index 157dc1b..4bdc0c5 100644
--- a/app/view/stdpage.php
+++ b/app/view/stdpage.php
@@ -17,7 +17,6 @@ namespace stdpage;
require_once "class/globals.php";
?>
-
<?php function head(?string $title = NULL) : void { ?>
<!--
@@ -54,12 +53,14 @@ require_once "class/globals.php";
<title>Scrott<?=($title ? " - ".$title : "")?></title>
<link rel="stylesheet" type="text/css" href="<?=ar()?>/static/css/bootstrap.min.css" />
-<?php } ?>
-<?php function top() : void { ?>
<?php } ?>
+<?php function top() : void { ?>
+<?php } ?>
<?php function foot() : void { ?>
+
<script type="text/javascript" src="<?=ar()?>/static/js/jquery.min.js"></script>
<script type="text/javascript" src="<?=ar()?>/static/js/bootstrap.min.js"></script>
+
<?php } ?>