Initial commit

master
Garrett Mills 3 years ago
commit 5a54fe251d
Signed by: garrettmills
GPG Key ID: D2BF5FBA8298F246

@ -0,0 +1,17 @@
<?php
require './configuration.php';
$page = new common\Page;
$page->title('EECS 448 Lab 10 - Exercise 4')
->header('Admin Home')
->writes("
<ul>
<li><a href=\"" . system_url('ViewUsers.php') . "\">View Users</a></li>
<li><a href=\"" . system_url('ViewUserPosts.html') . "\">View Posts by User</a></li>
<li><a href=\"" . system_url('DeletePost.html') . "\">Delete Posts</a></li>
</ul>
");
$page->write();

@ -0,0 +1,16 @@
<?php
require_once './configuration.php';
$page = new common\Page;
$page->title('Exercise 3 - EECS 448 Lab 10')
->header('Create a New Post')
->div(function() use($page) {
$page->form(system_url('CreatePosts.php'), function() use($page) {
$page->writes('<input type="text" name="username" placeholder="Username" required/>')->line_break();
$page->writes('<textarea name="content" placeholder="Post content" required></textarea>')->line_break();
$page->submit();
});
})
->write();

@ -0,0 +1,35 @@
<?php
require_once './configuration.php';
$request = common\Request::capture();
$page = new common\Page;
$users = new app\UserRepository;
$posts = new app\PostRepository;
$page->title('Exercise 3 - EECS 448 Lab 10')
->header('Create a New Post');
if ( !$request->input('username') ) {
$page->fail_to('You must specify the username.', system_url('CreatePosts.html'));
}
if ( !$request->input('content') ) {
$page->fail_to('You must specify post content.', system_url('CreatePosts.html'));
}
$user = $users->find_one([ 'username' => $request->input('username') ]);
if ( !$user ) {
$page->fail_to('Sorry, a user with that username does not exist.', system_url('CreatePosts.html'));
}
$post = $posts->save([
'user_id' => $user['user_id'],
'content' => $request->input('content'),
]);
$page->div(function() use($page) {
$page->writes('Post created successfully.');
});
$page->write();

@ -0,0 +1,14 @@
<?php
require_once './configuration.php';
$page = new common\Page();
$page->title('Exercise 2 - EECS 448 Lab 10')
->header('Create a New User')
->form(system_url('CreateUser.php'), function() use($page) {
$page->writes('<input type="text" placeholder="Username" name="username" required/>');
$page->submit();
});
$page->write();

@ -0,0 +1,29 @@
<?php
require_once './configuration.php';
$request = common\Request::capture();
$page = new common\Page;
$users = new app\UserRepository;
$page->title('Exercise 2 - EECS 448 Lab 10')
->header('Create a New User');
if ( !$request->input('username') ) {
$page->fail_to('You must specify a username.', system_url('CreateUser.html'));
}
$existing_user = $users->find_one([ 'username' => $request->input('username') ]);
if ( $existing_user ) {
$page->fail_to('A user with that username already exists.', system_url('CreateUser.html'));
}
$new_user = $users->save([
'username' => $request->input('username'),
]);
$page->div(function() use($page, $new_user) {
$page->writes('User ' . $new_user['username'] . ' created successfully.');
});
$page->write();

@ -0,0 +1,41 @@
<?php
require './configuration.php';
$db = new common\database\Connection;
$db->connect();
$page = new common\Page;
$page->title('EECS 448 Lab 10 - Exercise 7')
->header('Delete Posts');
$query = "SELECT post.post_id, user.username, post.content
FROM posts post
LEFT JOIN users user
ON user.user_id = post.post_id";
$results = $db->fetch($query);
$post_display = array_merge([
['Post ID', 'Username', 'Content', 'Delete?'],
], array_map(function($post) {
$id = 'post-' . $post['post_id'];
return [
$post['post_id'],
$post['username'],
$post['content'],
'<input type="checkbox" id="' . $id . '" name="' . $id . '" value="yes">
<label for="' . $id . '">Delete</label>'
];
}, $results));
$page->writes('<p>Select the posts you want to delete.')
->form(system_url('DeletePost.php'), function() use($page, $post_display) {
$page->table($post_display)
->writes('<br>')
->submit();
});
$page->write();

@ -0,0 +1,24 @@
<?php
require './configuration.php';
$request = common\Request::capture();
$page = new common\Page;
$posts = new app\PostRepository;
$post_ids = [];
foreach ( $request->input() as $post_key => $value ) {
if ( $value !== 'yes' ) continue;
$post_id = explode('-', $post_key)[1];
$post_ids[] = $post_id;
$posts->delete(['post_id' => $post_id]);
}
$page->title('EECS 448 Lab 10 - Exercise 7')
->header('Posts Deleted')
->writes('<p>Posts with the following IDs were deleted: ' . implode(', ', $post_ids) . '</p>')
->writes('<a href="' . system_url('AdminHome.html') . '">Admin Home</a>');
$page->write();

@ -0,0 +1,26 @@
<?php
require './configuration.php';
$page = new common\Page;
$users = new app\UserRepository;
// Generate the user options
$user_options = array_map(function($user) {
return '<option value="' . $user['user_id'] . '">' . $user['username'] . '</option>';
}, $users->find());
$page->title('EECS 448 Lab 10 - Exercise 6')
->header('View Posts by User')
->form(system_url('ViewUserPosts.php'), function() use($page, $user_options) {
$page->writes('
<label for="user-select">Select a user:</label>
<select name="user_id" id="user-select" style="min-width: 300px;" required>
' . implode("\n", $user_options) . '
</select>
');
$page->submit();
});
$page->write();

@ -0,0 +1,44 @@
<?php
require './configuration.php';
$request = common\Request::capture();
$page = new common\Page;
$users = new app\UserRepository;
$posts = new app\PostRepository;
$page->title('EECS 448 Lab 10 - Exercise 6')
->header('View Posts by User');
if ( !$request->input('user_id') ) {
$page->fail_to('Please select a user.', system_url('ViewUserPosts.html'));
}
$user = $users->find_by_id($request->input('user_id'));
if ( !$user ) {
$page->fail_to('Invalid user.', system_url('ViewUserPosts.html'));
}
$user_posts = $posts->find([
'user_id' => $user['user_id'],
]);
$post_display = array_merge([
['Post ID', 'Post Content']
], array_map(function($post) {
return [$post['post_id'], $post['content']];
}, $user_posts));
$page->div(function() use($page, $user) {
$page->writes('<b>Posts by ' . $user['username'] . ':</b>');
});
$page->table($post_display);
$page->div(function() use($page) {
$page->writes('<a href="' . system_url('ViewUserPosts.html') . '">Select a different user</a>');
});
$page->write();

@ -0,0 +1,23 @@
<?php
require './configuration.php';
$page = new common\Page;
$users = new app\UserRepository;
$page->title('EECS 448 Lab 10 - Exercise 5')
->header('View Registered Users');
$registered_users = $users->find();
$table_display = array_merge([
// Add the table headers
['User ID', 'Username'],
], array_map(function($user) {
// Map from associative array to keyed
return array_values($user);
}, $registered_users));
$page->table($table_display);
$page->write();

@ -0,0 +1,11 @@
<?php
namespace app;
use common\database\Repository;
class PostRepository extends Repository {
protected $table = 'posts';
protected $primary_key = 'post_id';
protected $fields = ['post_id', 'user_id', 'content'];
}

@ -0,0 +1,11 @@
<?php
namespace app;
use common\database\Repository;
class UserRepository extends Repository {
protected $table = 'users';
protected $primary_key = 'user_id';
protected $fields = ['user_id', 'username'];
}

@ -0,0 +1,28 @@
table, th, td {
border: 1px solid darkgrey;
border-collapse: collapse;
}
th, td {
padding: 10px;
}
div.common-page {
margin: 15px;
}
input {
padding: 5px;
margin: 10px;
}
button[type=submit] {
padding: 5px;
}
textarea {
margin: 10px;
padding: 5px;
min-width: 400px;
min-height: 200px;
}

@ -0,0 +1,208 @@
<?php
namespace common;
class Page {
protected $_title;
protected $_writers = [];
protected $_wrote_pre = false;
protected $_wrote_post = false;
protected $_writing = false;
protected $_scripts = [];
protected $_styles = [];
public function calls(callable $writer) {
$this->_writers[] = $writer;
if ( $this->_writing ) {
$writer();
}
return $this;
}
public function writes($string) {
$this->calls(function() use($string) {
echo $string;
});
return $this;
}
public function script($src) {
$this->_scripts[] = $src;
return $this;
}
public function stylesheet($src) {
$this->_styles[] = $src;
return $this;
}
public function title($title = null) {
if ( $title ) {
$this->_title = $title;
return $this;
} else {
return $this->_title;
}
}
public function header($string = null) {
if ( !$string ) $string = $this->title();
return $this->writes('<h1>' . $string . '</h1>');
}
public function form($submit, callable $inner) {
$this->writes('<form method="POST" action="' . $submit . '">');
$this->calls($inner);
$this->writes('</form>');
return $this;
}
public function submit($text = 'Submit') {
$this->writes('<button type="submit">' . $text . '</button>');
}
public function div(callable $inner) {
$this->writes('<div class="common-page">');
$this->calls($inner);
$this->writes('</div>');
return $this;
}
public function line_break() {
$this->writes('<br/>');
return $this;
}
public function table($nested_array) {
if ( is_array($nested_array) ) {
$this->calls(function() use($nested_array) {
echo '<table style="width: 100%;">';
foreach ( $nested_array as $row_idx => $row ) {
echo '<tr>';
foreach ( $row as $col_idx => $col ) {
$tag = $row_idx === 0 ? 'th' : 'td';
echo "<{$tag}>{$col}</{$tag}>";
}
echo '</tr>';
}
echo '</table>';
});
} else {
$this->writes('<table style="width: 100%;">');
$this->calls($nested_array);
$this->writes('</table>');
}
return $this;
}
public function table_row_cell(callable $inner, $span = 1) {
$this->table_row(function() use($inner, $span) {
$this->writes('<td colspan="' . $span . '">');
$this->calls($inner);
$this->writes('</td>');
});
return $this;
}
public function table_row($inner = null) {
$this->writes('<tr>');
if ( $inner ) $this->calls($inner);
$this->writes('</tr>');
return $this;
}
public function table_head(callable $inner) {
$this->writes('<th>');
$this->calls($inner);
$this->writes('</th>');
return $this;
}
public function table_cell($inner = null) {
$this->writes('<td>');
if ( $inner ) $this->calls($inner);
$this->writes('</td>');
return $this;
}
public function fail_to($message, $redirect_url) {
$this->writes('<p>' . $message . '</p>')
->writes('<p><a href="' . $redirect_url . '">Try Again</a></p>')
->write();
exit;
}
public function preamble() {
if ( $this->_wrote_pre ) return;
$this->_styles[] = system_url('assets/common.css');
$styles = [];
foreach ( $this->_styles as $style ) {
$styles[] = '<link rel="stylesheet" href="' . $style . '"/>';
}
?>
<!DOCTYPE html>
<html>
<head>
<title><?= $this->_title ?></title>
<?= implode("\n", $styles) ?>
</head>
<body>
<?php
$this->_wrote_pre = true;
}
public function postamble() {
if ( $this->_wrote_post ) return;
$scripts = [];
foreach ( $this->_scripts as $script ) {
$scripts[] = '<script src="' . $script . '"></script>';
}
?>
<?= implode("\n", $scripts) ?>
</body>
</html>
<?php
$this->_wrote_post = true;
}
public function write() {
$this->_writing = true;
$this->preamble();
foreach ( $this->_writers as $writer ) {
$writer();
}
$this->postamble();
$this->_writing = false;
}
public function compile() {
ob_start();
$this->_wrote_pre = false;
$this->_wrote_post = false;
$this->write();
$this->_wrote_pre = false;
$this->_wrote_post = false;
return ob_get_clean();
}
}

@ -0,0 +1,40 @@
<?php
namespace common;
class Request {
protected $_get = [];
protected $_post = [];
public static function capture() {
$req = new static();
$req->_get = $_GET;
$req->_post = $_POST;
return $req;
}
public function input($path = null) {
if ( !$path ) {
return array_merge($this->_get, $this->_post);
}
$path_parts = explode('.', $path);
$get_value = $this->_get;
foreach ( $path_parts as $part ) {
if ( $get_value ) {
$get_value = $get_value[$part];
}
}
$post_value = $this->_post;
foreach ( $path_parts as $part ) {
if ( $post_value ) {
$post_value = $post_value[$part];
}
}
if ( $get_value ) return $get_value;
if ( $post_value ) return $post_value;
}
}

@ -0,0 +1,20 @@
<?php
class AutoLoad {
public static function load($class_name) {
$file = str_replace("\\", '/', $class_name) . '.php';
$path = system_path($file);
if ( file_exists($path) ) {
include_system($file, false);
if ( class_exists($class_name) ) {
return true;
}
}
return false;
}
}
spl_autoload_register('AutoLoad::load');

@ -0,0 +1,81 @@
<?php
namespace common\database;
class Connection {
protected static $mysqli;
protected $config;
function __construct() {
$this->config = config('database');
}
public function connect() {
if ( !static::$mysqli ) {
static::$mysqli = new \mysqli(
$this->config['url'],
$this->config['username'],
$this->config['password'],
$this->config['database']
);
}
if ( static::$mysqli->connect_errno ) {
throw new \Exception('Unable to connect to database: ' . static::$mysqli->connect_error);
}
}
public function escape($value) {
return static::$mysqli->real_escape_string($value);
}
public function execute($query, $args = [], $returns_statement = false) {
$statement = static::$mysqli->prepare($query);
if ( sizeof($args) > 0 ) {
$types = '';
foreach ( $args as $arg ) {
if ( is_int($arg) ) {
$types .= 'i';
} else if ( is_float($arg) || is_double($arg) ) {
$types .= 'd';
} else if ( is_string($arg) ) {
$types .= 's';
} else {
$types .= 'b';
}
}
$statement->bind_param($types, ...$args);
}
$statement->execute();
if ( $returns_statement ) return $statement;
return $statement->get_result();
}
public function insert($query, $args = []) {
$statement = $this->execute($query, $args, true);
return $statement->insert_id;
}
public function fetch($query, $args = []) {
$result = $this->execute($query, $args);
$rows = [];
while ( $row = $result->fetch_assoc() ) {
$rows[] = $row;
}
return $rows;
}
public function close() {
if ( static::$mysqli ) {
static::$mysqli->close();
static::$mysqli = null;
}
}
}

@ -0,0 +1,134 @@
<?php
namespace common\database;
class Repository {
protected $table;
protected $primary_key;
protected $fields = [];
protected $connection;
function __construct() {
$this->connection = new Connection();
$this->connection->connect();
}
function __destruct() {
$this->connection->close();
}
public function create($record) {
$fields = [];
$arg_parts = [];
$args = [];
foreach ( $this->fields as $field ) {
if ( isset($record[$field]) ) {
$fields[] = $field;
$args[] = $record[$field];
$arg_parts[] = '?';
}
}
$query = 'INSERT INTO ' . $this->table . ' (' . implode(', ', $fields) . ') VALUES (' . implode(', ', $arg_parts) . ')';
$insert_id = $this->connection->insert($query, $args);
$record[$this->primary_key] = $insert_id;
return $record;
}
public function find_by_id($primary_key) {
$query = 'SELECT ' . implode(', ', $this->fields) . ' FROM ' . $this->table . ' WHERE ' . $this->primary_key . ' = ?';
$results = $this->connection->fetch($query, [$primary_key]);
if ( sizeof($results) > 0 ) {
return $results[0];
}
}
public function find($filter = []) {
$query = 'SELECT ' . implode(', ', $this->fields) . ' FROM ' . $this->table . ' WHERE ';
list($wheres, $where_args) = $this->build_wheres_from_filter($filter);
$query .= implode(' AND ', $wheres);
$query .= ' ORDER BY ' . $this->primary_key . ' ASC';
return $this->connection->fetch($query, $where_args);
}
public function find_one($filter = []) {
$query = 'SELECT ' . implode(', ', $this->fields) . ' FROM ' . $this->table . ' WHERE ';
list($wheres, $where_args) = $this->build_wheres_from_filter($filter);
$query .= implode(' AND ', $wheres) . ' LIMIT 1';
$results = $this->connection->fetch($query, $where_args);
if ( sizeof($results) > 0 ) {
return $results[0];
}
}
public function update($record) {
$query = 'UPDATE ' . $this->table . ' SET ';
$query_args = [];
$sets = [];
foreach ( $this->fields as $field ) {
if ( isset($record[$field]) ) {
$sets[] = $field . '=?';
$query_args[] = $record[$field];
}
}
$query = 'UPDATE ' . $this->table . ' SET ' . implode(', ', $sets) . ' WHERE ' . $this->primary_key . ' = ?';
$query_args[] = $record[$this->primary_key];
$this->connection->execute($query, $query_args);
return $record;
}
public function save($record) {
if ( isset($record[$this->primary_key]) ) {
return $this->update($record);
} else {
return $this->create($record);
}
}
public function delete($record) {
$primary_key = $record[$this->primary_key];
$query = 'DELETE FROM ' . $this->table . ' WHERE ' . $this->primary_key . ' = ?';
$this->connection->execute($query, [$primary_key]);
}
protected function build_wheres_from_filter($filter = []) {
if ( !$filter ) {
return [['1=1'], []];
}
$wheres = [];
$where_args = [];
foreach ( $this->fields as $field ) {
if ( isset($filter[$field]) ) {
$val = $filter[$field];
if ( is_string($val) || is_numeric($val) ) {
$wheres[] = $field . ' = ?';
$where_args[] = $val;
} else if ( is_array($val) ) {
$where_items = [];
foreach ( $val as $item ) {
$where_items[] = '?';
$where_args[] = $item;
}
$wheres[] = $field . ' IN (' . implode(',', $where_items) . ')';
}
}
}
return [$wheres, $where_args];
}
}

@ -0,0 +1,18 @@
<?php
function config($path, $default_value = null) {
$parts = explode('.', $path);
if ( !$parts[0] ) {
return $default_value;
}
$config = require_system('config/' . $parts[0] . '.php');
foreach ( $parts as $i => $part ) {
if ( $i !== 0 && $config ) {
$config = $config[$part];
}
}
return $config;
}

@ -0,0 +1,8 @@
<?php
function dd($something) {
echo "<pre><code>";
var_dump($something);
echo "</code></pre>";
exit;
}

@ -0,0 +1,54 @@
<?php
function system_root() {
$root = dirname(dirname(__FILE__));
return $root;
}
function system_path($path) {
if ( $path[0] === '/' ) {
$path = substr($path, 1);
}
return implode('/', [system_root(), $path]);
}
function require_system($path, $once = true) {
if ( $once ) {
return require_once system_path($path);
} else {
return require system_path($path);
}
}
function include_system($path, $once = true) {
if ( $once ) {
return include_once system_path($path);
} else {
return include system_path($path);
}
}
function system_url($path) {
if ( $path[0] === '/' ) {
$path = substr($path, 1);
}
return implode('/', [SYSTEM_URL, $path]);
}
function system_redirect($path) {
header('Location: ' . system_url($path));
exit;
}
function no_direct_access() {
$key = array_search(__FUNCTION__, array_column(debug_backtrace(), 'function'));
$caller_file = debug_backtrace()[$key]['file'];
if ( $caller_file === $_SERVER['SCRIPT_FILENAME'] ) {
header("HTTP/1.1 401 Unauthorized");
echo 'Forbidden';
exit;
}
}

@ -0,0 +1,8 @@
<?php
return [
'url' => 'mysql.eecs.ku.edu',
'username' => 'garretmills',
'password' => '', // omitted for public repo
'database' => 'garretmills',
];

@ -0,0 +1,11 @@
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
!defined('SYSTEM_URL') && define('SYSTEM_URL', 'https://people.eecs.ku.edu/~g582m300/eecs448-lab10');
include_once dirname(__FILE__).'/common/functions_debugging.php';
include_once dirname(__FILE__).'/common/functions_system.php';
include_once dirname(__FILE__).'/common/functions_config.php';
include_once dirname(__FILE__).'/common/autoload.php';

@ -0,0 +1,10 @@
<html>
<body>
<h1>Simple Posts</h1>
<ul>
<li><a href="CreateUser.html">Create User</a></li>
<li><a href="CreatePosts.html">Create Post</a></li>
<li><a href="AdminHome.html">Admin Home</a></li>
</ul>
</body>
</html>
Loading…
Cancel
Save