PHP based GroupMe bot with sqlite and control panel

The name of the pictureThe name of the pictureThe name of the pictureClash Royale CLAN TAG#URR8PPP





.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty margin-bottom:0;







up vote
0
down vote

favorite












I made a lot of updates to my GroupMe bot, now it uses sqlite and has a web panel. I'm wondering if there are any bad coding techniques used and more importantly if there are any security issues with it.
https://github.com/desultory/GroupMe-Bot



bot.php:



<?php
//Includes all functions and parses the post data into appropriate variables
include 'functions.php';
include 'lights.php';

$callback = json_decode(file_get_contents('php://input'));
$attachments = $callback->attachments;
$avatar = $callback->avatar_url;
$name = $callback->name;
$type = $callback->sender_type;
$text = $callback->text;
$userid = $callback->user_id;

$admins = get_admins();
$ignored = get_ignored();
$settings = get_settings();

//If logging is enabled in the config, this logs the chat to the database
logging($userid, $name, $text);

//Only handles messages from users to prevent infinite loops
if ($type == 'user' && !in_array($userid, $ignored) && $text[0] != '/')
//Basic response is a simple response to a found phrase
basic_response($text, $name, $userid);
//If the Weather Underground API token and location are set and weather has been enabled, this will return a forecast if someone says "weather"
if ($settings['weather'])
weather_response($text);

//If anyone says "bitcoin" and the bitcoin setting is enabled, this will return the price in USD
if ($settings['bitcoin'])
btc_response($text);

//If anyone says "ethereum" and the ethereum setting is enabled, this will return the price in USD and BTC
if ($settings['ethereum'])
eth_response($text);

//If anyone says "litecoin" and the litecoin setting is enabled, this will return the price in USD and BTC
if ($settings['litecoin'])
ltc_response($text);

if ($settings['lights'])
blink($ip, $pins, "50", "20");


if (in_array($userid, $admins) && $type == 'user' && $text == '/config')



functions.php:



<?php
//Writes the contents of a variable to a text file for debugging purposes
function debugvar($variable)
file_put_contents('debug.txt', print_r($variable, true));

//Initialize the database
function initdb()
$db = new PDO('sqlite:db.sqlite');
$dbcmds = ['CREATE TABLE IF NOT EXISTS config(
name TEXT NOT NULL,
value TEXT NOT NULL
)',
'CREATE TABLE IF NOT EXISTS settings(
name TEXT NOT NULL,
value INTEGER NOT NULL
)',
'CREATE TABLE IF NOT EXISTS responses(
find TEXT NOT NULL,
respond TEXT NOT NULL
)',
'CREATE TABLE IF NOT EXISTS users(
name TEXT NOT NULL,
userid TEXT NOT NULL,
admin INTEGER,
ignored INTEGER
)',
'CREATE TABLE IF NOT EXISTS auth(
username TEXT NOT NULL,
password TEXT NOT NULL
)',
'CREATE TABLE IF NOT EXISTS log(
entry TEXT NOT NULL,
timestamp INTEGER NOT NULL
)',
];
foreach ($dbcmds as $cmd)
$db->exec($cmd);

$clean = 1;
foreach ($db->errorInfo() as $error)
if ($error != 0)
$clean = $error;


return $clean;

//Gets the specified config variable value from the database
function get_config_var($parameter)
$db = new PDO('sqlite:db.sqlite');
$query = $db->prepare('SELECT value FROM config WHERE name=:name');
$query->bindValue(':name', $parameter, PDO::PARAM_STR);
$query->execute();
$result = $query->fetch(PDO::FETCH_ASSOC);
return $result['value'];

//Returns panel admins as an array
function get_panel_admins()
$db = new PDO('sqlite:db.sqlite');
$query = $db->prepare('SELECT username FROM auth');
$query->execute();
$result = $query->fetchAll(PDO::FETCH_COLUMN, 0);
return $result;

//Adds admins listed in array
function add_admin($user, $pass)
$db = new PDO('sqlite:db.sqlite');
$admins = get_panel_admins();
$username = strtolower($user);
$password = password_hash($pass, PASSWORD_DEFAULT);
if (!in_array($username, $admins))
$query = $db->prepare('INSERT INTO auth (username, password) VALUES (:username, :password)');
$query->bindValue(':username', $username, PDO::PARAM_STR);
$query->bindValue(':password', $password, PDO::PARAM_STR);
$query->execute();
else
echo "Admin already exists";


//Changes an admin password to the specified password
function change_admin_pass($users)
$db = new PDO('sqlite:db.sqlite');
foreach ($users as $name=>$pass)
if (!empty($pass))
$username = strtolower($name);
$password = password_hash($pass, PASSWORD_DEFAULT);
$query = $db->prepare('UPDATE auth set password=:password WHERE username=:username');
$query->bindValue(':username', $username, PDO::PARAM_STR);
$query->bindValue(':password', $password, PDO::PARAM_STR);
$query->execute();



//Deletes admins listed in array
function delete_admin($delete)
$db = new PDO('sqlite:db.sqlite');
foreach ($delete as $name)
$query = $db->prepare('SELECT count(username) FROM auth');
$query->execute();
$count = $query->fetch();
$count = $count[0];
if ($count > '1')
$username = strtolower($name);
$query = $db->prepare('DELETE FROM auth WHERE username=:name');
$query->bindValue(':name', $username, PDO::PARAM_STR);
$query->execute();
else
echo "Cannot delete last admin";



//Returns the responses as an array
function get_responses()
$db = new PDO('sqlite:db.sqlite');
$query = $db->prepare('SELECT find,respond FROM responses');
$query->execute();
return $query->fetchAll();

//Returns the config as an array
function get_config()
$db = new PDO('sqlite:db.sqlite');
$query = $db->prepare('SELECT name,value FROM config');
$query->execute();
return $query->fetchAll();

//Returns the chat log
function get_log()
$db = new PDO('sqlite:db.sqlite');
$query = $db->prepare('SELECT entry,timestamp FROM log');
$query->execute();
return $query->fetchAll();

//Returns the admins as an array
function get_admins()
$db = new PDO('sqlite:db.sqlite');
$query = $db->prepare('SELECT userid FROM users WHERE admin=1');
$query->execute();
return $query->fetchAll(PDO::FETCH_COLUMN, 0);

//Returns the ignored users as an array
function get_ignored()
$db = new PDO('sqlite:db.sqlite');
$query = $db->prepare('SELECT userid FROM users WHERE ignored=1');
$query->execute();
return $query->fetchAll(PDO::FETCH_COLUMN, 0);

//Returns the settings as an array
function get_settings()
$db = new PDO('sqlite:db.sqlite');
$query = $db->prepare('SELECT name,value FROM settings');
$query->execute();
$result = $query->fetchAll();
foreach ($result as $setting)
$settings[$setting[0]] = $setting[1];

return $settings;

//Logs all chat to the database
function logging($userid, $name, $text)
$db = new PDO('sqlite:db.sqlite');
if (get_config_var('log'))
$entry = "$name($userid): $text";
$statement = $db->prepare('INSERT INTO log (entry, timestamp) VALUES (:entry, :timestamp)');
$statement->bindValue(':entry', $entry, PDO::PARAM_STR);
$statement->bindValue(':timestamp', time(), PDO::PARAM_STR);
$statement->execute();



//Basic response (no images)
function basic_response($text, $name, $userid)
$responses = get_responses();
foreach ($responses as $element)
if (stripos($text, $element[0]) !== FALSE)
$message = $element[1];
$message = str_replace('%u', $userid, $message);
if (stripos($message, '%n') !== FALSE)
$message = str_replace('%n', $name, $message);
mention($message, $name);
else
send($message);




//WUnderground response
function weather_response($text)
$wutoken = get_config_var('wutoken');
$wuloc = get_config_var('wuloc');
if (stripos($text, 'weather') !== FALSE)
if (isset($wutoken) && isset($wuloc))
$rawweather = json_decode(curl_get("https://api.wunderground.com/api/$wutoken/conditions/q/$wuloc.json"));
$temperature = $rawweather->current_observation->feelslike_string;
$weather = $rawweather->current_observation->weather;
$icon = $rawweather->current_observation->icon_url;
$forecast = "The weather is $weather with a temperature of $temperature";
send_img($forecast, $icon);
else
send('WUnderground token and location are not set');



//Bitcoin value response
function btc_response($text)
if (stripos($text, 'bitcoin') !== FALSE)
$pricedata = json_decode(curl_get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD"));
$usdprice = $pricedata->USD;
$message = "Bitcoin is worth $$usdprice";
$btclogo = 'https://files.coinmarketcap.com/static/img/coins/32x32/bitcoin.png';
send_img($message, $btclogo);


//Ethereum value response
function eth_response($text)
if (stripos($text, 'ethereum') !== FALSE)
$pricedata = json_decode(curl_get("https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=BTC,USD"));
$usdprice = $pricedata->USD;
$btcprice = $pricedata->BTC;
$message = "Ethereum is worth $$usdprice and $btcprice Bitcoin";
$ethlogo = 'https://files.coinmarketcap.com/static/img/coins/32x32/ethereum.png';
send_img($message, $ethlogo);


//Litecoin value response
function ltc_response($text)
if (stripos($text, 'litecoin') !== FALSE)
$pricedata = json_decode(curl_get("https://min-api.cryptocompare.com/data/price?fsym=LTC&tsyms=BTC,USD"));
$usdprice = $pricedata->USD;
$btcprice = $pricedata->BTC;
$message = "Litecoin is worth $$usdprice and $btcprice Bitcoin";
$ltclogo = 'https://files.coinmarketcap.com/static/img/coins/32x32/litecoin.png';
send_img($message, $ltclogo);


//Curl get function, takes url and returns the get response
function curl_get($url)
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "$url");
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$get = curl_exec($ch);
curl_close($ch);
return $get;

//Curl post to groupme, takes the postfields and posts to the groupme bot api
function curl_post($postfields)
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.groupme.com/v3/bots/post');
curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields);
curl_exec($ch);
curl_close($ch);

//Send message function, takes a message as input and posts to GroupMe
function send($message)
$bottoken = get_config_var('bottoken');
$postdata = [
'bot_id' => $bottoken,
'text' => $message
];
curl_post(http_build_query($postdata));

//Send image function, takes message and img url as inputs and posts to GroupMe
function send_img($message, $image)
$bottoken = get_config_var('bottoken');
$attachments = [
'type' => 'image',
'url' => $image
];
$postdata = [
'bot_id' => $bottoken,
'text' => $message,
'attachments' => [$attachments]
];
curl_post(json_encode($postdata));

//Mention function, takes a message and name as inputs and posts to GroupMe
function mention($message, $name)
$bottoken = get_config_var('bottoken');
$loci = [
stripos($message, $name),
strlen($name)
];
$attachments = [
'loci' => [$loci],
'type' => 'mentions',
'user_ids' => [get_user_id($name)]
];
$postdata = [
'bot_id' => $bottoken,
'text' => $message,
'attachments' => [$attachments]
];
curl_post(json_encode($postdata));

//Get bot group function, returns the group id of the bot
function get_bot_group()
$apitoken = get_config_var('apitoken');
$bottoken = get_config_var('bottoken');
$bots = json_decode(curl_get("https://api.groupme.com/v3/bots?token=$apitoken"));
foreach($bots->response as $element)
if ($element->bot_id == $bottoken)
return $element->group_id;



//Get user id function, takes a name as input and returns the user id
function get_user_id($name)
$apitoken = get_config_var('apitoken');
$user_id = 'No member with that name found';
$groupid = get_bot_group();
$groups = json_decode(curl_get("https://api.groupme.com/v3/groups?token=$apitoken"));
foreach($groups->response as $element)
if ($element->id == $groupid)
foreach($element->members as $member)
if (stripos($member->nickname, $name) !== FALSE)
$user_id = $member->user_id;




return $user_id;

//Get name function, takes a user id as input and returns the name associated with that user id
function get_name($userid)
$apitoken = get_config_var('apitoken');
$name = 'Invalid userid';
$groupid = get_bot_group();
$groups = json_decode(curl_get("https://api.groupme.com/v3/groups?token=$apitoken"));
foreach($groups->response as $element)
if ($element->id == $groupid)
foreach($element->members as $member)
if ($userid == $member->user_id)
$name = $member->nickname;




return $name;

//Get users function, gets user information from the groupme api, adds it to the database, and returns it as an array
function get_users()
$apitoken = get_config_var('apitoken');
$groupid = get_bot_group();
$groups = json_decode(curl_get("https://api.groupme.com/v3/groups?token=$apitoken"));
$index = 0;
$db = new PDO('sqlite:db.sqlite');
foreach($groups->response as $element)
if ($element->id == $groupid)
foreach($element->members as $member)
$userid = $member->user_id;
$name = $member->nickname;
$avatar = $member->image_url;
$query = $db->prepare('SELECT userid FROM users WHERE userid=:userid');
$query->bindValue('userid', $userid, PDO::PARAM_STR);
$query->execute();
$result = $query->fetch(PDO::FETCH_ASSOC);
if (isset($result['userid']))
$query = $db->prepare('UPDATE users SET name=:name WHERE userid=:userid');
$query->bindValue(':name', $name, PDO::PARAM_STR);
$query->bindValue(':userid', $userid, PDO::PARAM_STR);
$query->execute();
else
$query = $db->prepare('INSERT INTO users (name, userid) VALUES (:name, :userid)');
$query->bindValue(':name', $name, PDO::PARAM_STR);
$query->bindValue(':userid', $userid, PDO::PARAM_STR);
$query->execute();

$members[$index] = [
"userid" => $userid,
"name" => $name,
"avatar" => $avatar
];
$index++;



return $members;

//Adds a response to the database, uses input find and respond where find is the text that is searched for and respond is the text that is retrned
function add_response($find, $respond)
$responses = get_responses();
$exists = 0;
foreach ($responses as $element)
if (stripos($element[0], $find) !== FALSE
if (!$exists)
$db = new PDO('sqlite:db.sqlite');
$query = $db->prepare('INSERT INTO responses (find, respond) VALUES (:find, :respond)');
$query->bindValue(':find', $find, PDO::PARAM_STR);
$query->bindValue(':respond', $respond, PDO::PARAM_STR);
$query->execute();
else
echo "Similar find already exists<br>";



//Deletes responses from the database, takes the "find" string as input
function del_responses($delete)
$db = new PDO('sqlite:db.sqlite');
foreach ($delete as $find)
$query = $db->prepare('DELETE FROM responses WHERE find=:find');
$query->bindValue(':find', $find, PDO::PARAM_STR);
$query->execute();


//Deletes all admins from the database
function delete_admins()
$db = new PDO('sqlite:db.sqlite');
$query = $db->prepare('UPDATE users SET admin = 0');
$query->execute();

//Updates the admins by deleting all of them and then adding the specified userids
function update_admins($admins)
delete_admins();
$db = new PDO('sqlite:db.sqlite');
foreach ($admins as $element)
$query = $db->prepare('UPDATE users SET admin=:admin WHERE userid=:userid');
$query->bindValue(':userid', $element, PDO::PARAM_STR);
$query->bindValue(':admin', '1', PDO::PARAM_STR);
$query->execute();


//Deletes all ignored users from the database
function delete_ignored()
$db = new PDO('sqlite:db.sqlite');
$query = $db->prepare('UPDATE users SET ignored = 0');
$query->execute();

//Updates the users by deleting all of them and then adding the specified userids
function update_ignored($ignored)
delete_ignored();
$db = new PDO('sqlite:db.sqlite');
foreach ($ignored as $element)
$query = $db->prepare('UPDATE users SET ignored=:ignored WHERE userid=:userid');
$query->bindValue(':userid', $element, PDO::PARAM_STR);
$query->bindValue(':ignored', '1', PDO::PARAM_STR);
$query->execute();


//Resets all settings in the database
function reset_settings()
$db = new PDO('sqlite:db.sqlite');
$query = $db->prepare('UPDATE settings SET value = 0');
$query->execute();

//Updates the settings by restting all of the settings and then enabling the specified ones
function update_settings($settings)
reset_settings();
$db = new PDO('sqlite:db.sqlite');
foreach ($settings as $element)
$query = $db->prepare('UPDATE settings SET value=:value WHERE name=:name');
$query->bindValue(':name', $element, PDO::PARAM_STR);
$query->bindValue(':value', '1', PDO::PARAM_STR);
$query->execute();


//Adds the specified setting to the array if it doesn't already exist
function add_setting($setting)
$settings = get_settings();
$exists = 0;
foreach ($settings as $element=>$key)
if ($setting == $element)
$exists = 1;


if (!$exists)
$db = new PDO('sqlite:db.sqlite');
$query = $db->prepare('INSERT INTO settings (name, value) VALUES (:name, :value)');
$query->bindValue(':name', $setting, PDO::PARAM_STR);
$query->bindValue(':value', '1', PDO::PARAM_STR);
$query->execute();
else
echo "Setting already exists<br>";



//Deletes responses from the database, takes the "find" string as input
function del_settings($delete)
$db = new PDO('sqlite:db.sqlite');
foreach ($delete as $setting)
$query = $db->prepare('DELETE FROM settings WHERE name=:setting');
$query->bindValue(':setting', $setting, PDO::PARAM_STR);
$query->execute();


//Updates the config, takes an array of config paramaters with the element name being the paramter and the value being the value
function update_config($config)
$db = new PDO('sqlite:db.sqlite');
foreach ($config as $name=>$value)
if ($value[0] != "*")
$query = $db->prepare('UPDATE config SET value=:value WHERE name=:name');
$query->bindValue(':name', $name, PDO::PARAM_STR);
$query->bindValue(':value', $value, PDO::PARAM_STR);
$query->execute();



//Display the setup form
function disp_setup()
$setup = <<<'EOSETUP'
<form name="setup" method="post" action="">
<table align="center" style="width: 50%;">
<tr>
<td>Panel username:</td>
<td><input type="text" style="width: 100%;" name="user" placeholder="Panel username" required></td>
</tr>
<tr>
<td>Panel password:</td>
<td><input type="password" style="width: 100%;" name="pass" placeholder="Panel password" required></td>
</tr>
<tr>
<td>GroupMe API token:</td>
<td><input type="text" style="width: 100%;" name="apitoken" placeholder="Your GroupMe API token" required></td>
</tr>
<tr>
<td>GroupMe Bot token:</td>
<td><input type="text" style="width: 100%;" name="bottoken" placeholder="Your GroupMe Bot token" required></td>
</tr>
<tr>
<td>WeatherUnderground API token:</td>
<td><input type="text" style="width: 100%;" name="wutoken" placeholder="Your WeatherUnderground API token" value=""></td>
</tr>
<tr>
<td>WeatherUnderground location code:</td>
<td><input type="text" style="width: 100%;" name="wuloc" placeholder="Your WeatherUnderground location code" value=""></td>
</tr>
<tr>
<td>Logging, check to enable</td>
<td><input type="checkbox" style="width: 100%;" name="log" value="1" checked required></td>
</tr>
<tr>
<td colspan="3"><input type="submit" value="Initialize"></td>
</tr>
</table>
</form>
EOSETUP;
echo $setup;

//Display the login
function disp_login()
$login = <<<'EOLOGIN'
<form name="login" method="post" action="">
<table align="center" style="width: 50%;">
<tr>
<td>Username:</td>
<td><input type="text" style="width: 100%;" name="username" placeholder="Panel username" required></td>
</tr>
<tr>
<td>Password:</td>
<td><input type="password" style="width: 100%;" name="password" placeholder="Panel password" required></td>
</tr>
<tr>
<td colspan="3"><input type="submit" value="Login"></td>
</tr>
</table>
</form>
EOLOGIN;
echo $login;



index.php:



<!DOCTYPE html>
<html>
<head>
<style>
body
background: url("https://picload.org/image/dadcrgpl/background.png");
background-repeat: repeat-y;
background-size: cover;
color: white;
margin: 0;
padding: 0;
left: 0;
right: 0;
position: absolute;
font-size: 16px;
text-align: center;
font-family: "Lucida Console", Monaco, monospace;

form
border: 0;
margin: 0;

ul
list-style-type: none;
margin: 0;
padding: 0;
overflow: hidden;

li
float: left;
display: block;

summary
background: rgba(255, 0, 0, .1);
text-align: left;;
font-size: 18px;

table
max-width: 100%;
border-spacing: 0;
text-align: left;
font-size: 16px;

tr
max-width: 100%;

th, td
height: 100%;
padding: 10px;
overflow-x: hidden;
vertical-align: middle;

tr:nth-child(even)
background-color: rgba(255, 255, 255, 0.50);

tr:nth-child(odd)
background-color: rgba(255, 255, 255, 0.25);

input
border: 0;
box-sizing: border-box;
color: white;
text-indent: 0px;
font-size: 16px;
background: rgba(0, 0, 0, 0);
font-family: "Lucida Console", Monaco, monospace;

</style>
<title>PHP GroupMe Bot</title>
</head>
<body>
<?php
header('Content-type: text/html; charset=utf-8');
ini_set('display_errors', 1);
ini_set('session.save_path', getcwd());
error_reporting(-1);
include 'functions.php';
session_start();
if (file_exists('db.sqlite'))
if (isset($_SESSION['username']))
if (isset($_POST['logout']))
session_destroy();
header("Refresh:1");

if (!empty($_POST['add_admin_name']) && !empty($_POST['add_admin_pass']))
add_admin($_POST['add_admin_name'], $_POST['add_admin_pass']);

if (isset($_POST['delete_admin']))
delete_admin($_POST['delete_admin']);

if (isset($_POST['change_admin_pass']))
change_admin_pass($_POST['change_admin_pass']);

if (isset($_POST['config']))
update_config($_POST['config']);

if (isset($_POST['find']) && isset($_POST['respond']) && !empty($_POST['find']) && !empty($_POST['respond']))
add_response($_POST['find'], $_POST['respond']);

if (isset($_POST['delete']))
del_responses($_POST['delete']);

if (isset($_POST['users']))
if (isset($_POST['admins']))
update_admins($_POST['admins']);
else
delete_admins();

if (isset($_POST['ignored']))
update_ignored($_POST['ignored']);
else
delete_ignored();


if (isset($_POST['settings']))
update_settings($_POST['settings']);

if (isset($_POST['new_setting']) && !empty($_POST['new_setting']))
add_setting($_POST['new_setting']);

if (isset($_POST['del_settings']) && !empty($_POST['del_settings']))
del_settings($_POST['del_settings']);

if (isset($_POST['send']) && !empty($_POST['send']))
send($_POST['send']);
?>
<div style="align: right; height: 5vh; background: rgba(0, 0, 0, .5);">
<ul>
<?php
$username = $_SESSION['username'];
echo "<li>$username Logged in</li>";
?>
<form name="logout" method="post" action="">
<li><input type="hidden" name="logout" value="logout"></li>
<input style="float: right;" type="submit" value="Log Out">
</form>
</div>
<div style="overflow-y: scroll; height: 90vh">
<details>
<summary>Panel</summary>
<form name="panel" method="post" action="">
<table align="center">
<tr>
<th>Panel Admins</th>
<th>Delete</th>
<th>Change Password</th>
</tr>
<?php
$admins = get_panel_admins();
foreach ($admins as $element)
$name = $element;
echo "<tr>";
echo "<td>$name</td>";
echo "<td><input type="checkbox" name="delete_admin" value="$name"></td>";
echo "<td><input type="password" name="change_admin_pass[$name]" placeholder="Password"></td>";
echo "</tr>";
?>
<tr>
<td><input type="text" name="add_admin_name" placeholder="Username"></td>
<td colspan="2"><input type="password" name="add_admin_pass" placeholder="Password"></td>
<tr>
<th colspan="3"><input type="submit" value="Update"></th>
</tr>
</table>
</form>
</details>
<details>
<summary>Config</summary>
<form name="config" method="post" action="">
<table align="center">
<tr>
<th>Setting</th>
<th>Value</th>
<th>New Value</th>
</tr>
<?php
$config = get_config();
foreach ($config as $element)
$name = $element['name'];
$value = $element['value'];
echo "<tr>";
echo "<td>$name</td>";
if (stripos($name, 'token') !== FALSE)
$value = str_repeat('*', strlen($value) - 4) . substr($value, -4);
echo "<td>$value</td>";
echo "<td><input type="text" name="config[$name]" value="$value"></td>";
else
echo "<td>$value</td>";
echo "<td><input type="text" name="config[$name]" value="$value"></td>";

echo "</tr>";
?>
<tr>
<th colspan="3"><input type="submit" value="Update"></th>
</tr>
</table>
</form>
</details>
<details>
<summary>Add</summary>
<form name="add" method="post" action="">
<h3>%n can be used to mention someone in a response</h3>
<table align="center">
<tr>
<th><input type="text" name="find" placeholder="Text to find"></th>
<th><input type="text" name="respond" placeholder="Text to respond with"></th>
<th><input type="submit" value="Add"></th>
</tr>
</table>
</form>
</details>
<details>
<summary>Delete</summary>
<form name="delete" method="post" action="">
<table align="center">
<tr>
<th>Find</th>
<th>Respond</th>
<th>Delete</th>
</tr>
<?php
$responses = get_responses();
foreach ($responses as $element)
$find = $element['find'];
$respond = $element['respond'];
echo "<tr>";
echo "<td>$find</td>";
echo "<td>$respond</td>";
echo "<td><input type="checkbox" name="delete" value="$find"></td>";
echo "</tr>";
?>
<tr>
<th colspan="3"><input type="submit" value="Remove"></th>
</tr>
</table>
</form>
</details>
<details>
<summary>Users</summary>
<form name="Users" method="post" action="">
<table align="center">
<tr>
<th>Name</th>
<th>Admin</th>
<th>Ignored</th>
</tr>
<?php
$admins = get_admins();
$ignored = get_ignored();
$users = get_users();
$i = 0;
foreach ($users as $user)
$name = htmlspecialchars($user["name"]);
$userid = htmlspecialchars($user["userid"]);
$avatar = $user["avatar"];
echo "<tr>";
echo "<td style="text-align: left;"><img src="$avatar" style="width:50px; height:50px; vertical-align: middle;">$name ($userid)</td>";
if (in_array($users[$i]['userid'], $admins))
echo "<td><input type="checkbox" name="admins" value="$userid" checked></td>";
else
echo "<td><input type="checkbox" name="admins" value="$userid"></td>";

if (in_array($users[$i]['userid'], $ignored))
echo "<td><input type="checkbox" name="ignored" value="$userid" checked></td>";
else
echo "<td><input type="checkbox" name="ignored" value="$userid"></td>";

echo "</tr>";
$i++;
?>
<tr>
<th colspan="3"><input type="submit" value="Update"></th>
</tr>
</table>
<input type="hidden" name="users" value="1">
</form>
</details>
<details>
<summary>Settings</summary>
<form name="settings" method="post" action="">
<table align="center">
<tr>
<th>Name</th>
<th>State</th>
<th>Delete</th>
</tr>
<?php
$settings = get_settings();
foreach ($settings as $element=>$key)
$name = $element;
$value = $key;
echo "<tr>";
echo "<td>$name</td>";
if ($value)
echo "<td><input type="checkbox" name="settings" value="$name" checked></td>";
else
echo "<td><input type="checkbox" name="settings" value="$name"></td>";

echo "<td><input type="checkbox" name="del_settings" value="$name"></td>";
echo "</tr>";
?>
<tr>
<td>Add setting</td>
<td colspan="2"><input type="text" name="new_setting" placeholder="Name for new setting"></td>
</tr>
<tr>
<th colspan="3"><input type="submit" value="Update"></th>
</tr>
</table>
<input type="hidden" name="settings" value="1">
</form>
</details>
<details>
<summary>Log</summary>
<table style="width: 100%;">
<?php
$log = get_log();
foreach ($log as $element)
$timestamp = date("Y-m-d@H:i:s", $element['timestamp']);
$entry = htmlspecialchars($element['entry']);
echo "<tr>";
echo "<td>$timestamp</td>";
echo "<td>$entry</td>";
echo "</tr>";
?>
</table>
</details>
</div>
<form name="send" method="post" action="">
<table style="width: 100%; position: fixed; bottom: 0; height: 5vh">
<tr>
<th><input type="text" name="send" placeholder="Message to send"></th>
</tr>
</table>
<input type="submit" value="Send" style="display: none">
</form>
<?php
else
disp_login();
if (isset($_POST['username']) && isset($_POST['password']))
$db = new PDO('sqlite:db.sqlite');
$username = strtolower($_POST['username']);
$password = $_POST['password'];
$query = $db->prepare('SELECT password FROM auth WHERE username=:username');
$query->bindValue(':username', $username, PDO::PARAM_STR);
$query->execute();
$hashed = $query->fetch(PDO::FETCH_COLUMN, 0);
if (password_verify($password, $hashed))
echo "Logging in...";
$_SESSION['username'] = $username;
header("Refresh:1");
else
echo "Incorrect password!";



else if (is_writeable('./'))
if (!empty($_POST) && initdb())
$db = new PDO('sqlite:db.sqlite');
$config = ['apitoken', 'bottoken', 'wutoken', 'wuloc'];
$settings = ['litecoin', 'bitcoin', 'ethereum'];
foreach($config as $variable)
$statement = $db->prepare('INSERT INTO config (name, value) VALUES (:name, :value)');
$statement->bindValue(':name', $variable, PDO::PARAM_STR);
$statement->bindValue(':value', $_POST[$variable], PDO::PARAM_STR);
$statement->execute();

if ($_POST['log'])
$db->exec("INSERT INTO config (name, value) VALUES ('log', '1')");
else
$db->exec("INSERT INTO config (name, value) VALUES ('log', '1')");

if ((isset($_POST['wutoken'])) && isset($_POST['wuloc']))
$db->exec("INSERT INTO settings (name, value) VALUES ('weather', '1')");
else
$db->exec("INSERT INTO settings (name, value) VALUES ('weather', '0')");

$db->exec("INSERT INTO settings (name, value) VALUES ('lights', '0')");
$db->exec("INSERT INTO responses (find, respond) VALUES ('test', 'It works!')");
add_admin($_POST['user'], $_POST['pass']);
foreach($settings as $variable)
$statement = $db->prepare('INSERT INTO settings (name, value) VALUES (:name, :value)');
$statement->bindValue(':name', $variable, PDO::PARAM_STR);
$statement->bindValue(':value', '1', PDO::PARAM_STR);
$statement->execute();

file_put_contents('.htaccess', "<Files "db.sqlite">nDeny From Alln</Files>n<Files "sess*">nDeny From Alln</Files>");
header("Refresh:1");

disp_setup();
else
echo "Working directory is not writeable, either chown it to the webserver user and group or allow write permissions to everyone (insecure!)";
?>
</body>
</html>






share|improve this question

























    up vote
    0
    down vote

    favorite












    I made a lot of updates to my GroupMe bot, now it uses sqlite and has a web panel. I'm wondering if there are any bad coding techniques used and more importantly if there are any security issues with it.
    https://github.com/desultory/GroupMe-Bot



    bot.php:



    <?php
    //Includes all functions and parses the post data into appropriate variables
    include 'functions.php';
    include 'lights.php';

    $callback = json_decode(file_get_contents('php://input'));
    $attachments = $callback->attachments;
    $avatar = $callback->avatar_url;
    $name = $callback->name;
    $type = $callback->sender_type;
    $text = $callback->text;
    $userid = $callback->user_id;

    $admins = get_admins();
    $ignored = get_ignored();
    $settings = get_settings();

    //If logging is enabled in the config, this logs the chat to the database
    logging($userid, $name, $text);

    //Only handles messages from users to prevent infinite loops
    if ($type == 'user' && !in_array($userid, $ignored) && $text[0] != '/')
    //Basic response is a simple response to a found phrase
    basic_response($text, $name, $userid);
    //If the Weather Underground API token and location are set and weather has been enabled, this will return a forecast if someone says "weather"
    if ($settings['weather'])
    weather_response($text);

    //If anyone says "bitcoin" and the bitcoin setting is enabled, this will return the price in USD
    if ($settings['bitcoin'])
    btc_response($text);

    //If anyone says "ethereum" and the ethereum setting is enabled, this will return the price in USD and BTC
    if ($settings['ethereum'])
    eth_response($text);

    //If anyone says "litecoin" and the litecoin setting is enabled, this will return the price in USD and BTC
    if ($settings['litecoin'])
    ltc_response($text);

    if ($settings['lights'])
    blink($ip, $pins, "50", "20");


    if (in_array($userid, $admins) && $type == 'user' && $text == '/config')



    functions.php:



    <?php
    //Writes the contents of a variable to a text file for debugging purposes
    function debugvar($variable)
    file_put_contents('debug.txt', print_r($variable, true));

    //Initialize the database
    function initdb()
    $db = new PDO('sqlite:db.sqlite');
    $dbcmds = ['CREATE TABLE IF NOT EXISTS config(
    name TEXT NOT NULL,
    value TEXT NOT NULL
    )',
    'CREATE TABLE IF NOT EXISTS settings(
    name TEXT NOT NULL,
    value INTEGER NOT NULL
    )',
    'CREATE TABLE IF NOT EXISTS responses(
    find TEXT NOT NULL,
    respond TEXT NOT NULL
    )',
    'CREATE TABLE IF NOT EXISTS users(
    name TEXT NOT NULL,
    userid TEXT NOT NULL,
    admin INTEGER,
    ignored INTEGER
    )',
    'CREATE TABLE IF NOT EXISTS auth(
    username TEXT NOT NULL,
    password TEXT NOT NULL
    )',
    'CREATE TABLE IF NOT EXISTS log(
    entry TEXT NOT NULL,
    timestamp INTEGER NOT NULL
    )',
    ];
    foreach ($dbcmds as $cmd)
    $db->exec($cmd);

    $clean = 1;
    foreach ($db->errorInfo() as $error)
    if ($error != 0)
    $clean = $error;


    return $clean;

    //Gets the specified config variable value from the database
    function get_config_var($parameter)
    $db = new PDO('sqlite:db.sqlite');
    $query = $db->prepare('SELECT value FROM config WHERE name=:name');
    $query->bindValue(':name', $parameter, PDO::PARAM_STR);
    $query->execute();
    $result = $query->fetch(PDO::FETCH_ASSOC);
    return $result['value'];

    //Returns panel admins as an array
    function get_panel_admins()
    $db = new PDO('sqlite:db.sqlite');
    $query = $db->prepare('SELECT username FROM auth');
    $query->execute();
    $result = $query->fetchAll(PDO::FETCH_COLUMN, 0);
    return $result;

    //Adds admins listed in array
    function add_admin($user, $pass)
    $db = new PDO('sqlite:db.sqlite');
    $admins = get_panel_admins();
    $username = strtolower($user);
    $password = password_hash($pass, PASSWORD_DEFAULT);
    if (!in_array($username, $admins))
    $query = $db->prepare('INSERT INTO auth (username, password) VALUES (:username, :password)');
    $query->bindValue(':username', $username, PDO::PARAM_STR);
    $query->bindValue(':password', $password, PDO::PARAM_STR);
    $query->execute();
    else
    echo "Admin already exists";


    //Changes an admin password to the specified password
    function change_admin_pass($users)
    $db = new PDO('sqlite:db.sqlite');
    foreach ($users as $name=>$pass)
    if (!empty($pass))
    $username = strtolower($name);
    $password = password_hash($pass, PASSWORD_DEFAULT);
    $query = $db->prepare('UPDATE auth set password=:password WHERE username=:username');
    $query->bindValue(':username', $username, PDO::PARAM_STR);
    $query->bindValue(':password', $password, PDO::PARAM_STR);
    $query->execute();



    //Deletes admins listed in array
    function delete_admin($delete)
    $db = new PDO('sqlite:db.sqlite');
    foreach ($delete as $name)
    $query = $db->prepare('SELECT count(username) FROM auth');
    $query->execute();
    $count = $query->fetch();
    $count = $count[0];
    if ($count > '1')
    $username = strtolower($name);
    $query = $db->prepare('DELETE FROM auth WHERE username=:name');
    $query->bindValue(':name', $username, PDO::PARAM_STR);
    $query->execute();
    else
    echo "Cannot delete last admin";



    //Returns the responses as an array
    function get_responses()
    $db = new PDO('sqlite:db.sqlite');
    $query = $db->prepare('SELECT find,respond FROM responses');
    $query->execute();
    return $query->fetchAll();

    //Returns the config as an array
    function get_config()
    $db = new PDO('sqlite:db.sqlite');
    $query = $db->prepare('SELECT name,value FROM config');
    $query->execute();
    return $query->fetchAll();

    //Returns the chat log
    function get_log()
    $db = new PDO('sqlite:db.sqlite');
    $query = $db->prepare('SELECT entry,timestamp FROM log');
    $query->execute();
    return $query->fetchAll();

    //Returns the admins as an array
    function get_admins()
    $db = new PDO('sqlite:db.sqlite');
    $query = $db->prepare('SELECT userid FROM users WHERE admin=1');
    $query->execute();
    return $query->fetchAll(PDO::FETCH_COLUMN, 0);

    //Returns the ignored users as an array
    function get_ignored()
    $db = new PDO('sqlite:db.sqlite');
    $query = $db->prepare('SELECT userid FROM users WHERE ignored=1');
    $query->execute();
    return $query->fetchAll(PDO::FETCH_COLUMN, 0);

    //Returns the settings as an array
    function get_settings()
    $db = new PDO('sqlite:db.sqlite');
    $query = $db->prepare('SELECT name,value FROM settings');
    $query->execute();
    $result = $query->fetchAll();
    foreach ($result as $setting)
    $settings[$setting[0]] = $setting[1];

    return $settings;

    //Logs all chat to the database
    function logging($userid, $name, $text)
    $db = new PDO('sqlite:db.sqlite');
    if (get_config_var('log'))
    $entry = "$name($userid): $text";
    $statement = $db->prepare('INSERT INTO log (entry, timestamp) VALUES (:entry, :timestamp)');
    $statement->bindValue(':entry', $entry, PDO::PARAM_STR);
    $statement->bindValue(':timestamp', time(), PDO::PARAM_STR);
    $statement->execute();



    //Basic response (no images)
    function basic_response($text, $name, $userid)
    $responses = get_responses();
    foreach ($responses as $element)
    if (stripos($text, $element[0]) !== FALSE)
    $message = $element[1];
    $message = str_replace('%u', $userid, $message);
    if (stripos($message, '%n') !== FALSE)
    $message = str_replace('%n', $name, $message);
    mention($message, $name);
    else
    send($message);




    //WUnderground response
    function weather_response($text)
    $wutoken = get_config_var('wutoken');
    $wuloc = get_config_var('wuloc');
    if (stripos($text, 'weather') !== FALSE)
    if (isset($wutoken) && isset($wuloc))
    $rawweather = json_decode(curl_get("https://api.wunderground.com/api/$wutoken/conditions/q/$wuloc.json"));
    $temperature = $rawweather->current_observation->feelslike_string;
    $weather = $rawweather->current_observation->weather;
    $icon = $rawweather->current_observation->icon_url;
    $forecast = "The weather is $weather with a temperature of $temperature";
    send_img($forecast, $icon);
    else
    send('WUnderground token and location are not set');



    //Bitcoin value response
    function btc_response($text)
    if (stripos($text, 'bitcoin') !== FALSE)
    $pricedata = json_decode(curl_get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD"));
    $usdprice = $pricedata->USD;
    $message = "Bitcoin is worth $$usdprice";
    $btclogo = 'https://files.coinmarketcap.com/static/img/coins/32x32/bitcoin.png';
    send_img($message, $btclogo);


    //Ethereum value response
    function eth_response($text)
    if (stripos($text, 'ethereum') !== FALSE)
    $pricedata = json_decode(curl_get("https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=BTC,USD"));
    $usdprice = $pricedata->USD;
    $btcprice = $pricedata->BTC;
    $message = "Ethereum is worth $$usdprice and $btcprice Bitcoin";
    $ethlogo = 'https://files.coinmarketcap.com/static/img/coins/32x32/ethereum.png';
    send_img($message, $ethlogo);


    //Litecoin value response
    function ltc_response($text)
    if (stripos($text, 'litecoin') !== FALSE)
    $pricedata = json_decode(curl_get("https://min-api.cryptocompare.com/data/price?fsym=LTC&tsyms=BTC,USD"));
    $usdprice = $pricedata->USD;
    $btcprice = $pricedata->BTC;
    $message = "Litecoin is worth $$usdprice and $btcprice Bitcoin";
    $ltclogo = 'https://files.coinmarketcap.com/static/img/coins/32x32/litecoin.png';
    send_img($message, $ltclogo);


    //Curl get function, takes url and returns the get response
    function curl_get($url)
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "$url");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    $get = curl_exec($ch);
    curl_close($ch);
    return $get;

    //Curl post to groupme, takes the postfields and posts to the groupme bot api
    function curl_post($postfields)
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, 'https://api.groupme.com/v3/bots/post');
    curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields);
    curl_exec($ch);
    curl_close($ch);

    //Send message function, takes a message as input and posts to GroupMe
    function send($message)
    $bottoken = get_config_var('bottoken');
    $postdata = [
    'bot_id' => $bottoken,
    'text' => $message
    ];
    curl_post(http_build_query($postdata));

    //Send image function, takes message and img url as inputs and posts to GroupMe
    function send_img($message, $image)
    $bottoken = get_config_var('bottoken');
    $attachments = [
    'type' => 'image',
    'url' => $image
    ];
    $postdata = [
    'bot_id' => $bottoken,
    'text' => $message,
    'attachments' => [$attachments]
    ];
    curl_post(json_encode($postdata));

    //Mention function, takes a message and name as inputs and posts to GroupMe
    function mention($message, $name)
    $bottoken = get_config_var('bottoken');
    $loci = [
    stripos($message, $name),
    strlen($name)
    ];
    $attachments = [
    'loci' => [$loci],
    'type' => 'mentions',
    'user_ids' => [get_user_id($name)]
    ];
    $postdata = [
    'bot_id' => $bottoken,
    'text' => $message,
    'attachments' => [$attachments]
    ];
    curl_post(json_encode($postdata));

    //Get bot group function, returns the group id of the bot
    function get_bot_group()
    $apitoken = get_config_var('apitoken');
    $bottoken = get_config_var('bottoken');
    $bots = json_decode(curl_get("https://api.groupme.com/v3/bots?token=$apitoken"));
    foreach($bots->response as $element)
    if ($element->bot_id == $bottoken)
    return $element->group_id;



    //Get user id function, takes a name as input and returns the user id
    function get_user_id($name)
    $apitoken = get_config_var('apitoken');
    $user_id = 'No member with that name found';
    $groupid = get_bot_group();
    $groups = json_decode(curl_get("https://api.groupme.com/v3/groups?token=$apitoken"));
    foreach($groups->response as $element)
    if ($element->id == $groupid)
    foreach($element->members as $member)
    if (stripos($member->nickname, $name) !== FALSE)
    $user_id = $member->user_id;




    return $user_id;

    //Get name function, takes a user id as input and returns the name associated with that user id
    function get_name($userid)
    $apitoken = get_config_var('apitoken');
    $name = 'Invalid userid';
    $groupid = get_bot_group();
    $groups = json_decode(curl_get("https://api.groupme.com/v3/groups?token=$apitoken"));
    foreach($groups->response as $element)
    if ($element->id == $groupid)
    foreach($element->members as $member)
    if ($userid == $member->user_id)
    $name = $member->nickname;




    return $name;

    //Get users function, gets user information from the groupme api, adds it to the database, and returns it as an array
    function get_users()
    $apitoken = get_config_var('apitoken');
    $groupid = get_bot_group();
    $groups = json_decode(curl_get("https://api.groupme.com/v3/groups?token=$apitoken"));
    $index = 0;
    $db = new PDO('sqlite:db.sqlite');
    foreach($groups->response as $element)
    if ($element->id == $groupid)
    foreach($element->members as $member)
    $userid = $member->user_id;
    $name = $member->nickname;
    $avatar = $member->image_url;
    $query = $db->prepare('SELECT userid FROM users WHERE userid=:userid');
    $query->bindValue('userid', $userid, PDO::PARAM_STR);
    $query->execute();
    $result = $query->fetch(PDO::FETCH_ASSOC);
    if (isset($result['userid']))
    $query = $db->prepare('UPDATE users SET name=:name WHERE userid=:userid');
    $query->bindValue(':name', $name, PDO::PARAM_STR);
    $query->bindValue(':userid', $userid, PDO::PARAM_STR);
    $query->execute();
    else
    $query = $db->prepare('INSERT INTO users (name, userid) VALUES (:name, :userid)');
    $query->bindValue(':name', $name, PDO::PARAM_STR);
    $query->bindValue(':userid', $userid, PDO::PARAM_STR);
    $query->execute();

    $members[$index] = [
    "userid" => $userid,
    "name" => $name,
    "avatar" => $avatar
    ];
    $index++;



    return $members;

    //Adds a response to the database, uses input find and respond where find is the text that is searched for and respond is the text that is retrned
    function add_response($find, $respond)
    $responses = get_responses();
    $exists = 0;
    foreach ($responses as $element)
    if (stripos($element[0], $find) !== FALSE
    if (!$exists)
    $db = new PDO('sqlite:db.sqlite');
    $query = $db->prepare('INSERT INTO responses (find, respond) VALUES (:find, :respond)');
    $query->bindValue(':find', $find, PDO::PARAM_STR);
    $query->bindValue(':respond', $respond, PDO::PARAM_STR);
    $query->execute();
    else
    echo "Similar find already exists<br>";



    //Deletes responses from the database, takes the "find" string as input
    function del_responses($delete)
    $db = new PDO('sqlite:db.sqlite');
    foreach ($delete as $find)
    $query = $db->prepare('DELETE FROM responses WHERE find=:find');
    $query->bindValue(':find', $find, PDO::PARAM_STR);
    $query->execute();


    //Deletes all admins from the database
    function delete_admins()
    $db = new PDO('sqlite:db.sqlite');
    $query = $db->prepare('UPDATE users SET admin = 0');
    $query->execute();

    //Updates the admins by deleting all of them and then adding the specified userids
    function update_admins($admins)
    delete_admins();
    $db = new PDO('sqlite:db.sqlite');
    foreach ($admins as $element)
    $query = $db->prepare('UPDATE users SET admin=:admin WHERE userid=:userid');
    $query->bindValue(':userid', $element, PDO::PARAM_STR);
    $query->bindValue(':admin', '1', PDO::PARAM_STR);
    $query->execute();


    //Deletes all ignored users from the database
    function delete_ignored()
    $db = new PDO('sqlite:db.sqlite');
    $query = $db->prepare('UPDATE users SET ignored = 0');
    $query->execute();

    //Updates the users by deleting all of them and then adding the specified userids
    function update_ignored($ignored)
    delete_ignored();
    $db = new PDO('sqlite:db.sqlite');
    foreach ($ignored as $element)
    $query = $db->prepare('UPDATE users SET ignored=:ignored WHERE userid=:userid');
    $query->bindValue(':userid', $element, PDO::PARAM_STR);
    $query->bindValue(':ignored', '1', PDO::PARAM_STR);
    $query->execute();


    //Resets all settings in the database
    function reset_settings()
    $db = new PDO('sqlite:db.sqlite');
    $query = $db->prepare('UPDATE settings SET value = 0');
    $query->execute();

    //Updates the settings by restting all of the settings and then enabling the specified ones
    function update_settings($settings)
    reset_settings();
    $db = new PDO('sqlite:db.sqlite');
    foreach ($settings as $element)
    $query = $db->prepare('UPDATE settings SET value=:value WHERE name=:name');
    $query->bindValue(':name', $element, PDO::PARAM_STR);
    $query->bindValue(':value', '1', PDO::PARAM_STR);
    $query->execute();


    //Adds the specified setting to the array if it doesn't already exist
    function add_setting($setting)
    $settings = get_settings();
    $exists = 0;
    foreach ($settings as $element=>$key)
    if ($setting == $element)
    $exists = 1;


    if (!$exists)
    $db = new PDO('sqlite:db.sqlite');
    $query = $db->prepare('INSERT INTO settings (name, value) VALUES (:name, :value)');
    $query->bindValue(':name', $setting, PDO::PARAM_STR);
    $query->bindValue(':value', '1', PDO::PARAM_STR);
    $query->execute();
    else
    echo "Setting already exists<br>";



    //Deletes responses from the database, takes the "find" string as input
    function del_settings($delete)
    $db = new PDO('sqlite:db.sqlite');
    foreach ($delete as $setting)
    $query = $db->prepare('DELETE FROM settings WHERE name=:setting');
    $query->bindValue(':setting', $setting, PDO::PARAM_STR);
    $query->execute();


    //Updates the config, takes an array of config paramaters with the element name being the paramter and the value being the value
    function update_config($config)
    $db = new PDO('sqlite:db.sqlite');
    foreach ($config as $name=>$value)
    if ($value[0] != "*")
    $query = $db->prepare('UPDATE config SET value=:value WHERE name=:name');
    $query->bindValue(':name', $name, PDO::PARAM_STR);
    $query->bindValue(':value', $value, PDO::PARAM_STR);
    $query->execute();



    //Display the setup form
    function disp_setup()
    $setup = <<<'EOSETUP'
    <form name="setup" method="post" action="">
    <table align="center" style="width: 50%;">
    <tr>
    <td>Panel username:</td>
    <td><input type="text" style="width: 100%;" name="user" placeholder="Panel username" required></td>
    </tr>
    <tr>
    <td>Panel password:</td>
    <td><input type="password" style="width: 100%;" name="pass" placeholder="Panel password" required></td>
    </tr>
    <tr>
    <td>GroupMe API token:</td>
    <td><input type="text" style="width: 100%;" name="apitoken" placeholder="Your GroupMe API token" required></td>
    </tr>
    <tr>
    <td>GroupMe Bot token:</td>
    <td><input type="text" style="width: 100%;" name="bottoken" placeholder="Your GroupMe Bot token" required></td>
    </tr>
    <tr>
    <td>WeatherUnderground API token:</td>
    <td><input type="text" style="width: 100%;" name="wutoken" placeholder="Your WeatherUnderground API token" value=""></td>
    </tr>
    <tr>
    <td>WeatherUnderground location code:</td>
    <td><input type="text" style="width: 100%;" name="wuloc" placeholder="Your WeatherUnderground location code" value=""></td>
    </tr>
    <tr>
    <td>Logging, check to enable</td>
    <td><input type="checkbox" style="width: 100%;" name="log" value="1" checked required></td>
    </tr>
    <tr>
    <td colspan="3"><input type="submit" value="Initialize"></td>
    </tr>
    </table>
    </form>
    EOSETUP;
    echo $setup;

    //Display the login
    function disp_login()
    $login = <<<'EOLOGIN'
    <form name="login" method="post" action="">
    <table align="center" style="width: 50%;">
    <tr>
    <td>Username:</td>
    <td><input type="text" style="width: 100%;" name="username" placeholder="Panel username" required></td>
    </tr>
    <tr>
    <td>Password:</td>
    <td><input type="password" style="width: 100%;" name="password" placeholder="Panel password" required></td>
    </tr>
    <tr>
    <td colspan="3"><input type="submit" value="Login"></td>
    </tr>
    </table>
    </form>
    EOLOGIN;
    echo $login;



    index.php:



    <!DOCTYPE html>
    <html>
    <head>
    <style>
    body
    background: url("https://picload.org/image/dadcrgpl/background.png");
    background-repeat: repeat-y;
    background-size: cover;
    color: white;
    margin: 0;
    padding: 0;
    left: 0;
    right: 0;
    position: absolute;
    font-size: 16px;
    text-align: center;
    font-family: "Lucida Console", Monaco, monospace;

    form
    border: 0;
    margin: 0;

    ul
    list-style-type: none;
    margin: 0;
    padding: 0;
    overflow: hidden;

    li
    float: left;
    display: block;

    summary
    background: rgba(255, 0, 0, .1);
    text-align: left;;
    font-size: 18px;

    table
    max-width: 100%;
    border-spacing: 0;
    text-align: left;
    font-size: 16px;

    tr
    max-width: 100%;

    th, td
    height: 100%;
    padding: 10px;
    overflow-x: hidden;
    vertical-align: middle;

    tr:nth-child(even)
    background-color: rgba(255, 255, 255, 0.50);

    tr:nth-child(odd)
    background-color: rgba(255, 255, 255, 0.25);

    input
    border: 0;
    box-sizing: border-box;
    color: white;
    text-indent: 0px;
    font-size: 16px;
    background: rgba(0, 0, 0, 0);
    font-family: "Lucida Console", Monaco, monospace;

    </style>
    <title>PHP GroupMe Bot</title>
    </head>
    <body>
    <?php
    header('Content-type: text/html; charset=utf-8');
    ini_set('display_errors', 1);
    ini_set('session.save_path', getcwd());
    error_reporting(-1);
    include 'functions.php';
    session_start();
    if (file_exists('db.sqlite'))
    if (isset($_SESSION['username']))
    if (isset($_POST['logout']))
    session_destroy();
    header("Refresh:1");

    if (!empty($_POST['add_admin_name']) && !empty($_POST['add_admin_pass']))
    add_admin($_POST['add_admin_name'], $_POST['add_admin_pass']);

    if (isset($_POST['delete_admin']))
    delete_admin($_POST['delete_admin']);

    if (isset($_POST['change_admin_pass']))
    change_admin_pass($_POST['change_admin_pass']);

    if (isset($_POST['config']))
    update_config($_POST['config']);

    if (isset($_POST['find']) && isset($_POST['respond']) && !empty($_POST['find']) && !empty($_POST['respond']))
    add_response($_POST['find'], $_POST['respond']);

    if (isset($_POST['delete']))
    del_responses($_POST['delete']);

    if (isset($_POST['users']))
    if (isset($_POST['admins']))
    update_admins($_POST['admins']);
    else
    delete_admins();

    if (isset($_POST['ignored']))
    update_ignored($_POST['ignored']);
    else
    delete_ignored();


    if (isset($_POST['settings']))
    update_settings($_POST['settings']);

    if (isset($_POST['new_setting']) && !empty($_POST['new_setting']))
    add_setting($_POST['new_setting']);

    if (isset($_POST['del_settings']) && !empty($_POST['del_settings']))
    del_settings($_POST['del_settings']);

    if (isset($_POST['send']) && !empty($_POST['send']))
    send($_POST['send']);
    ?>
    <div style="align: right; height: 5vh; background: rgba(0, 0, 0, .5);">
    <ul>
    <?php
    $username = $_SESSION['username'];
    echo "<li>$username Logged in</li>";
    ?>
    <form name="logout" method="post" action="">
    <li><input type="hidden" name="logout" value="logout"></li>
    <input style="float: right;" type="submit" value="Log Out">
    </form>
    </div>
    <div style="overflow-y: scroll; height: 90vh">
    <details>
    <summary>Panel</summary>
    <form name="panel" method="post" action="">
    <table align="center">
    <tr>
    <th>Panel Admins</th>
    <th>Delete</th>
    <th>Change Password</th>
    </tr>
    <?php
    $admins = get_panel_admins();
    foreach ($admins as $element)
    $name = $element;
    echo "<tr>";
    echo "<td>$name</td>";
    echo "<td><input type="checkbox" name="delete_admin" value="$name"></td>";
    echo "<td><input type="password" name="change_admin_pass[$name]" placeholder="Password"></td>";
    echo "</tr>";
    ?>
    <tr>
    <td><input type="text" name="add_admin_name" placeholder="Username"></td>
    <td colspan="2"><input type="password" name="add_admin_pass" placeholder="Password"></td>
    <tr>
    <th colspan="3"><input type="submit" value="Update"></th>
    </tr>
    </table>
    </form>
    </details>
    <details>
    <summary>Config</summary>
    <form name="config" method="post" action="">
    <table align="center">
    <tr>
    <th>Setting</th>
    <th>Value</th>
    <th>New Value</th>
    </tr>
    <?php
    $config = get_config();
    foreach ($config as $element)
    $name = $element['name'];
    $value = $element['value'];
    echo "<tr>";
    echo "<td>$name</td>";
    if (stripos($name, 'token') !== FALSE)
    $value = str_repeat('*', strlen($value) - 4) . substr($value, -4);
    echo "<td>$value</td>";
    echo "<td><input type="text" name="config[$name]" value="$value"></td>";
    else
    echo "<td>$value</td>";
    echo "<td><input type="text" name="config[$name]" value="$value"></td>";

    echo "</tr>";
    ?>
    <tr>
    <th colspan="3"><input type="submit" value="Update"></th>
    </tr>
    </table>
    </form>
    </details>
    <details>
    <summary>Add</summary>
    <form name="add" method="post" action="">
    <h3>%n can be used to mention someone in a response</h3>
    <table align="center">
    <tr>
    <th><input type="text" name="find" placeholder="Text to find"></th>
    <th><input type="text" name="respond" placeholder="Text to respond with"></th>
    <th><input type="submit" value="Add"></th>
    </tr>
    </table>
    </form>
    </details>
    <details>
    <summary>Delete</summary>
    <form name="delete" method="post" action="">
    <table align="center">
    <tr>
    <th>Find</th>
    <th>Respond</th>
    <th>Delete</th>
    </tr>
    <?php
    $responses = get_responses();
    foreach ($responses as $element)
    $find = $element['find'];
    $respond = $element['respond'];
    echo "<tr>";
    echo "<td>$find</td>";
    echo "<td>$respond</td>";
    echo "<td><input type="checkbox" name="delete" value="$find"></td>";
    echo "</tr>";
    ?>
    <tr>
    <th colspan="3"><input type="submit" value="Remove"></th>
    </tr>
    </table>
    </form>
    </details>
    <details>
    <summary>Users</summary>
    <form name="Users" method="post" action="">
    <table align="center">
    <tr>
    <th>Name</th>
    <th>Admin</th>
    <th>Ignored</th>
    </tr>
    <?php
    $admins = get_admins();
    $ignored = get_ignored();
    $users = get_users();
    $i = 0;
    foreach ($users as $user)
    $name = htmlspecialchars($user["name"]);
    $userid = htmlspecialchars($user["userid"]);
    $avatar = $user["avatar"];
    echo "<tr>";
    echo "<td style="text-align: left;"><img src="$avatar" style="width:50px; height:50px; vertical-align: middle;">$name ($userid)</td>";
    if (in_array($users[$i]['userid'], $admins))
    echo "<td><input type="checkbox" name="admins" value="$userid" checked></td>";
    else
    echo "<td><input type="checkbox" name="admins" value="$userid"></td>";

    if (in_array($users[$i]['userid'], $ignored))
    echo "<td><input type="checkbox" name="ignored" value="$userid" checked></td>";
    else
    echo "<td><input type="checkbox" name="ignored" value="$userid"></td>";

    echo "</tr>";
    $i++;
    ?>
    <tr>
    <th colspan="3"><input type="submit" value="Update"></th>
    </tr>
    </table>
    <input type="hidden" name="users" value="1">
    </form>
    </details>
    <details>
    <summary>Settings</summary>
    <form name="settings" method="post" action="">
    <table align="center">
    <tr>
    <th>Name</th>
    <th>State</th>
    <th>Delete</th>
    </tr>
    <?php
    $settings = get_settings();
    foreach ($settings as $element=>$key)
    $name = $element;
    $value = $key;
    echo "<tr>";
    echo "<td>$name</td>";
    if ($value)
    echo "<td><input type="checkbox" name="settings" value="$name" checked></td>";
    else
    echo "<td><input type="checkbox" name="settings" value="$name"></td>";

    echo "<td><input type="checkbox" name="del_settings" value="$name"></td>";
    echo "</tr>";
    ?>
    <tr>
    <td>Add setting</td>
    <td colspan="2"><input type="text" name="new_setting" placeholder="Name for new setting"></td>
    </tr>
    <tr>
    <th colspan="3"><input type="submit" value="Update"></th>
    </tr>
    </table>
    <input type="hidden" name="settings" value="1">
    </form>
    </details>
    <details>
    <summary>Log</summary>
    <table style="width: 100%;">
    <?php
    $log = get_log();
    foreach ($log as $element)
    $timestamp = date("Y-m-d@H:i:s", $element['timestamp']);
    $entry = htmlspecialchars($element['entry']);
    echo "<tr>";
    echo "<td>$timestamp</td>";
    echo "<td>$entry</td>";
    echo "</tr>";
    ?>
    </table>
    </details>
    </div>
    <form name="send" method="post" action="">
    <table style="width: 100%; position: fixed; bottom: 0; height: 5vh">
    <tr>
    <th><input type="text" name="send" placeholder="Message to send"></th>
    </tr>
    </table>
    <input type="submit" value="Send" style="display: none">
    </form>
    <?php
    else
    disp_login();
    if (isset($_POST['username']) && isset($_POST['password']))
    $db = new PDO('sqlite:db.sqlite');
    $username = strtolower($_POST['username']);
    $password = $_POST['password'];
    $query = $db->prepare('SELECT password FROM auth WHERE username=:username');
    $query->bindValue(':username', $username, PDO::PARAM_STR);
    $query->execute();
    $hashed = $query->fetch(PDO::FETCH_COLUMN, 0);
    if (password_verify($password, $hashed))
    echo "Logging in...";
    $_SESSION['username'] = $username;
    header("Refresh:1");
    else
    echo "Incorrect password!";



    else if (is_writeable('./'))
    if (!empty($_POST) && initdb())
    $db = new PDO('sqlite:db.sqlite');
    $config = ['apitoken', 'bottoken', 'wutoken', 'wuloc'];
    $settings = ['litecoin', 'bitcoin', 'ethereum'];
    foreach($config as $variable)
    $statement = $db->prepare('INSERT INTO config (name, value) VALUES (:name, :value)');
    $statement->bindValue(':name', $variable, PDO::PARAM_STR);
    $statement->bindValue(':value', $_POST[$variable], PDO::PARAM_STR);
    $statement->execute();

    if ($_POST['log'])
    $db->exec("INSERT INTO config (name, value) VALUES ('log', '1')");
    else
    $db->exec("INSERT INTO config (name, value) VALUES ('log', '1')");

    if ((isset($_POST['wutoken'])) && isset($_POST['wuloc']))
    $db->exec("INSERT INTO settings (name, value) VALUES ('weather', '1')");
    else
    $db->exec("INSERT INTO settings (name, value) VALUES ('weather', '0')");

    $db->exec("INSERT INTO settings (name, value) VALUES ('lights', '0')");
    $db->exec("INSERT INTO responses (find, respond) VALUES ('test', 'It works!')");
    add_admin($_POST['user'], $_POST['pass']);
    foreach($settings as $variable)
    $statement = $db->prepare('INSERT INTO settings (name, value) VALUES (:name, :value)');
    $statement->bindValue(':name', $variable, PDO::PARAM_STR);
    $statement->bindValue(':value', '1', PDO::PARAM_STR);
    $statement->execute();

    file_put_contents('.htaccess', "<Files "db.sqlite">nDeny From Alln</Files>n<Files "sess*">nDeny From Alln</Files>");
    header("Refresh:1");

    disp_setup();
    else
    echo "Working directory is not writeable, either chown it to the webserver user and group or allow write permissions to everyone (insecure!)";
    ?>
    </body>
    </html>






    share|improve this question





















      up vote
      0
      down vote

      favorite









      up vote
      0
      down vote

      favorite











      I made a lot of updates to my GroupMe bot, now it uses sqlite and has a web panel. I'm wondering if there are any bad coding techniques used and more importantly if there are any security issues with it.
      https://github.com/desultory/GroupMe-Bot



      bot.php:



      <?php
      //Includes all functions and parses the post data into appropriate variables
      include 'functions.php';
      include 'lights.php';

      $callback = json_decode(file_get_contents('php://input'));
      $attachments = $callback->attachments;
      $avatar = $callback->avatar_url;
      $name = $callback->name;
      $type = $callback->sender_type;
      $text = $callback->text;
      $userid = $callback->user_id;

      $admins = get_admins();
      $ignored = get_ignored();
      $settings = get_settings();

      //If logging is enabled in the config, this logs the chat to the database
      logging($userid, $name, $text);

      //Only handles messages from users to prevent infinite loops
      if ($type == 'user' && !in_array($userid, $ignored) && $text[0] != '/')
      //Basic response is a simple response to a found phrase
      basic_response($text, $name, $userid);
      //If the Weather Underground API token and location are set and weather has been enabled, this will return a forecast if someone says "weather"
      if ($settings['weather'])
      weather_response($text);

      //If anyone says "bitcoin" and the bitcoin setting is enabled, this will return the price in USD
      if ($settings['bitcoin'])
      btc_response($text);

      //If anyone says "ethereum" and the ethereum setting is enabled, this will return the price in USD and BTC
      if ($settings['ethereum'])
      eth_response($text);

      //If anyone says "litecoin" and the litecoin setting is enabled, this will return the price in USD and BTC
      if ($settings['litecoin'])
      ltc_response($text);

      if ($settings['lights'])
      blink($ip, $pins, "50", "20");


      if (in_array($userid, $admins) && $type == 'user' && $text == '/config')



      functions.php:



      <?php
      //Writes the contents of a variable to a text file for debugging purposes
      function debugvar($variable)
      file_put_contents('debug.txt', print_r($variable, true));

      //Initialize the database
      function initdb()
      $db = new PDO('sqlite:db.sqlite');
      $dbcmds = ['CREATE TABLE IF NOT EXISTS config(
      name TEXT NOT NULL,
      value TEXT NOT NULL
      )',
      'CREATE TABLE IF NOT EXISTS settings(
      name TEXT NOT NULL,
      value INTEGER NOT NULL
      )',
      'CREATE TABLE IF NOT EXISTS responses(
      find TEXT NOT NULL,
      respond TEXT NOT NULL
      )',
      'CREATE TABLE IF NOT EXISTS users(
      name TEXT NOT NULL,
      userid TEXT NOT NULL,
      admin INTEGER,
      ignored INTEGER
      )',
      'CREATE TABLE IF NOT EXISTS auth(
      username TEXT NOT NULL,
      password TEXT NOT NULL
      )',
      'CREATE TABLE IF NOT EXISTS log(
      entry TEXT NOT NULL,
      timestamp INTEGER NOT NULL
      )',
      ];
      foreach ($dbcmds as $cmd)
      $db->exec($cmd);

      $clean = 1;
      foreach ($db->errorInfo() as $error)
      if ($error != 0)
      $clean = $error;


      return $clean;

      //Gets the specified config variable value from the database
      function get_config_var($parameter)
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('SELECT value FROM config WHERE name=:name');
      $query->bindValue(':name', $parameter, PDO::PARAM_STR);
      $query->execute();
      $result = $query->fetch(PDO::FETCH_ASSOC);
      return $result['value'];

      //Returns panel admins as an array
      function get_panel_admins()
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('SELECT username FROM auth');
      $query->execute();
      $result = $query->fetchAll(PDO::FETCH_COLUMN, 0);
      return $result;

      //Adds admins listed in array
      function add_admin($user, $pass)
      $db = new PDO('sqlite:db.sqlite');
      $admins = get_panel_admins();
      $username = strtolower($user);
      $password = password_hash($pass, PASSWORD_DEFAULT);
      if (!in_array($username, $admins))
      $query = $db->prepare('INSERT INTO auth (username, password) VALUES (:username, :password)');
      $query->bindValue(':username', $username, PDO::PARAM_STR);
      $query->bindValue(':password', $password, PDO::PARAM_STR);
      $query->execute();
      else
      echo "Admin already exists";


      //Changes an admin password to the specified password
      function change_admin_pass($users)
      $db = new PDO('sqlite:db.sqlite');
      foreach ($users as $name=>$pass)
      if (!empty($pass))
      $username = strtolower($name);
      $password = password_hash($pass, PASSWORD_DEFAULT);
      $query = $db->prepare('UPDATE auth set password=:password WHERE username=:username');
      $query->bindValue(':username', $username, PDO::PARAM_STR);
      $query->bindValue(':password', $password, PDO::PARAM_STR);
      $query->execute();



      //Deletes admins listed in array
      function delete_admin($delete)
      $db = new PDO('sqlite:db.sqlite');
      foreach ($delete as $name)
      $query = $db->prepare('SELECT count(username) FROM auth');
      $query->execute();
      $count = $query->fetch();
      $count = $count[0];
      if ($count > '1')
      $username = strtolower($name);
      $query = $db->prepare('DELETE FROM auth WHERE username=:name');
      $query->bindValue(':name', $username, PDO::PARAM_STR);
      $query->execute();
      else
      echo "Cannot delete last admin";



      //Returns the responses as an array
      function get_responses()
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('SELECT find,respond FROM responses');
      $query->execute();
      return $query->fetchAll();

      //Returns the config as an array
      function get_config()
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('SELECT name,value FROM config');
      $query->execute();
      return $query->fetchAll();

      //Returns the chat log
      function get_log()
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('SELECT entry,timestamp FROM log');
      $query->execute();
      return $query->fetchAll();

      //Returns the admins as an array
      function get_admins()
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('SELECT userid FROM users WHERE admin=1');
      $query->execute();
      return $query->fetchAll(PDO::FETCH_COLUMN, 0);

      //Returns the ignored users as an array
      function get_ignored()
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('SELECT userid FROM users WHERE ignored=1');
      $query->execute();
      return $query->fetchAll(PDO::FETCH_COLUMN, 0);

      //Returns the settings as an array
      function get_settings()
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('SELECT name,value FROM settings');
      $query->execute();
      $result = $query->fetchAll();
      foreach ($result as $setting)
      $settings[$setting[0]] = $setting[1];

      return $settings;

      //Logs all chat to the database
      function logging($userid, $name, $text)
      $db = new PDO('sqlite:db.sqlite');
      if (get_config_var('log'))
      $entry = "$name($userid): $text";
      $statement = $db->prepare('INSERT INTO log (entry, timestamp) VALUES (:entry, :timestamp)');
      $statement->bindValue(':entry', $entry, PDO::PARAM_STR);
      $statement->bindValue(':timestamp', time(), PDO::PARAM_STR);
      $statement->execute();



      //Basic response (no images)
      function basic_response($text, $name, $userid)
      $responses = get_responses();
      foreach ($responses as $element)
      if (stripos($text, $element[0]) !== FALSE)
      $message = $element[1];
      $message = str_replace('%u', $userid, $message);
      if (stripos($message, '%n') !== FALSE)
      $message = str_replace('%n', $name, $message);
      mention($message, $name);
      else
      send($message);




      //WUnderground response
      function weather_response($text)
      $wutoken = get_config_var('wutoken');
      $wuloc = get_config_var('wuloc');
      if (stripos($text, 'weather') !== FALSE)
      if (isset($wutoken) && isset($wuloc))
      $rawweather = json_decode(curl_get("https://api.wunderground.com/api/$wutoken/conditions/q/$wuloc.json"));
      $temperature = $rawweather->current_observation->feelslike_string;
      $weather = $rawweather->current_observation->weather;
      $icon = $rawweather->current_observation->icon_url;
      $forecast = "The weather is $weather with a temperature of $temperature";
      send_img($forecast, $icon);
      else
      send('WUnderground token and location are not set');



      //Bitcoin value response
      function btc_response($text)
      if (stripos($text, 'bitcoin') !== FALSE)
      $pricedata = json_decode(curl_get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD"));
      $usdprice = $pricedata->USD;
      $message = "Bitcoin is worth $$usdprice";
      $btclogo = 'https://files.coinmarketcap.com/static/img/coins/32x32/bitcoin.png';
      send_img($message, $btclogo);


      //Ethereum value response
      function eth_response($text)
      if (stripos($text, 'ethereum') !== FALSE)
      $pricedata = json_decode(curl_get("https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=BTC,USD"));
      $usdprice = $pricedata->USD;
      $btcprice = $pricedata->BTC;
      $message = "Ethereum is worth $$usdprice and $btcprice Bitcoin";
      $ethlogo = 'https://files.coinmarketcap.com/static/img/coins/32x32/ethereum.png';
      send_img($message, $ethlogo);


      //Litecoin value response
      function ltc_response($text)
      if (stripos($text, 'litecoin') !== FALSE)
      $pricedata = json_decode(curl_get("https://min-api.cryptocompare.com/data/price?fsym=LTC&tsyms=BTC,USD"));
      $usdprice = $pricedata->USD;
      $btcprice = $pricedata->BTC;
      $message = "Litecoin is worth $$usdprice and $btcprice Bitcoin";
      $ltclogo = 'https://files.coinmarketcap.com/static/img/coins/32x32/litecoin.png';
      send_img($message, $ltclogo);


      //Curl get function, takes url and returns the get response
      function curl_get($url)
      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, "$url");
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
      $get = curl_exec($ch);
      curl_close($ch);
      return $get;

      //Curl post to groupme, takes the postfields and posts to the groupme bot api
      function curl_post($postfields)
      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, 'https://api.groupme.com/v3/bots/post');
      curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields);
      curl_exec($ch);
      curl_close($ch);

      //Send message function, takes a message as input and posts to GroupMe
      function send($message)
      $bottoken = get_config_var('bottoken');
      $postdata = [
      'bot_id' => $bottoken,
      'text' => $message
      ];
      curl_post(http_build_query($postdata));

      //Send image function, takes message and img url as inputs and posts to GroupMe
      function send_img($message, $image)
      $bottoken = get_config_var('bottoken');
      $attachments = [
      'type' => 'image',
      'url' => $image
      ];
      $postdata = [
      'bot_id' => $bottoken,
      'text' => $message,
      'attachments' => [$attachments]
      ];
      curl_post(json_encode($postdata));

      //Mention function, takes a message and name as inputs and posts to GroupMe
      function mention($message, $name)
      $bottoken = get_config_var('bottoken');
      $loci = [
      stripos($message, $name),
      strlen($name)
      ];
      $attachments = [
      'loci' => [$loci],
      'type' => 'mentions',
      'user_ids' => [get_user_id($name)]
      ];
      $postdata = [
      'bot_id' => $bottoken,
      'text' => $message,
      'attachments' => [$attachments]
      ];
      curl_post(json_encode($postdata));

      //Get bot group function, returns the group id of the bot
      function get_bot_group()
      $apitoken = get_config_var('apitoken');
      $bottoken = get_config_var('bottoken');
      $bots = json_decode(curl_get("https://api.groupme.com/v3/bots?token=$apitoken"));
      foreach($bots->response as $element)
      if ($element->bot_id == $bottoken)
      return $element->group_id;



      //Get user id function, takes a name as input and returns the user id
      function get_user_id($name)
      $apitoken = get_config_var('apitoken');
      $user_id = 'No member with that name found';
      $groupid = get_bot_group();
      $groups = json_decode(curl_get("https://api.groupme.com/v3/groups?token=$apitoken"));
      foreach($groups->response as $element)
      if ($element->id == $groupid)
      foreach($element->members as $member)
      if (stripos($member->nickname, $name) !== FALSE)
      $user_id = $member->user_id;




      return $user_id;

      //Get name function, takes a user id as input and returns the name associated with that user id
      function get_name($userid)
      $apitoken = get_config_var('apitoken');
      $name = 'Invalid userid';
      $groupid = get_bot_group();
      $groups = json_decode(curl_get("https://api.groupme.com/v3/groups?token=$apitoken"));
      foreach($groups->response as $element)
      if ($element->id == $groupid)
      foreach($element->members as $member)
      if ($userid == $member->user_id)
      $name = $member->nickname;




      return $name;

      //Get users function, gets user information from the groupme api, adds it to the database, and returns it as an array
      function get_users()
      $apitoken = get_config_var('apitoken');
      $groupid = get_bot_group();
      $groups = json_decode(curl_get("https://api.groupme.com/v3/groups?token=$apitoken"));
      $index = 0;
      $db = new PDO('sqlite:db.sqlite');
      foreach($groups->response as $element)
      if ($element->id == $groupid)
      foreach($element->members as $member)
      $userid = $member->user_id;
      $name = $member->nickname;
      $avatar = $member->image_url;
      $query = $db->prepare('SELECT userid FROM users WHERE userid=:userid');
      $query->bindValue('userid', $userid, PDO::PARAM_STR);
      $query->execute();
      $result = $query->fetch(PDO::FETCH_ASSOC);
      if (isset($result['userid']))
      $query = $db->prepare('UPDATE users SET name=:name WHERE userid=:userid');
      $query->bindValue(':name', $name, PDO::PARAM_STR);
      $query->bindValue(':userid', $userid, PDO::PARAM_STR);
      $query->execute();
      else
      $query = $db->prepare('INSERT INTO users (name, userid) VALUES (:name, :userid)');
      $query->bindValue(':name', $name, PDO::PARAM_STR);
      $query->bindValue(':userid', $userid, PDO::PARAM_STR);
      $query->execute();

      $members[$index] = [
      "userid" => $userid,
      "name" => $name,
      "avatar" => $avatar
      ];
      $index++;



      return $members;

      //Adds a response to the database, uses input find and respond where find is the text that is searched for and respond is the text that is retrned
      function add_response($find, $respond)
      $responses = get_responses();
      $exists = 0;
      foreach ($responses as $element)
      if (stripos($element[0], $find) !== FALSE
      if (!$exists)
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('INSERT INTO responses (find, respond) VALUES (:find, :respond)');
      $query->bindValue(':find', $find, PDO::PARAM_STR);
      $query->bindValue(':respond', $respond, PDO::PARAM_STR);
      $query->execute();
      else
      echo "Similar find already exists<br>";



      //Deletes responses from the database, takes the "find" string as input
      function del_responses($delete)
      $db = new PDO('sqlite:db.sqlite');
      foreach ($delete as $find)
      $query = $db->prepare('DELETE FROM responses WHERE find=:find');
      $query->bindValue(':find', $find, PDO::PARAM_STR);
      $query->execute();


      //Deletes all admins from the database
      function delete_admins()
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('UPDATE users SET admin = 0');
      $query->execute();

      //Updates the admins by deleting all of them and then adding the specified userids
      function update_admins($admins)
      delete_admins();
      $db = new PDO('sqlite:db.sqlite');
      foreach ($admins as $element)
      $query = $db->prepare('UPDATE users SET admin=:admin WHERE userid=:userid');
      $query->bindValue(':userid', $element, PDO::PARAM_STR);
      $query->bindValue(':admin', '1', PDO::PARAM_STR);
      $query->execute();


      //Deletes all ignored users from the database
      function delete_ignored()
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('UPDATE users SET ignored = 0');
      $query->execute();

      //Updates the users by deleting all of them and then adding the specified userids
      function update_ignored($ignored)
      delete_ignored();
      $db = new PDO('sqlite:db.sqlite');
      foreach ($ignored as $element)
      $query = $db->prepare('UPDATE users SET ignored=:ignored WHERE userid=:userid');
      $query->bindValue(':userid', $element, PDO::PARAM_STR);
      $query->bindValue(':ignored', '1', PDO::PARAM_STR);
      $query->execute();


      //Resets all settings in the database
      function reset_settings()
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('UPDATE settings SET value = 0');
      $query->execute();

      //Updates the settings by restting all of the settings and then enabling the specified ones
      function update_settings($settings)
      reset_settings();
      $db = new PDO('sqlite:db.sqlite');
      foreach ($settings as $element)
      $query = $db->prepare('UPDATE settings SET value=:value WHERE name=:name');
      $query->bindValue(':name', $element, PDO::PARAM_STR);
      $query->bindValue(':value', '1', PDO::PARAM_STR);
      $query->execute();


      //Adds the specified setting to the array if it doesn't already exist
      function add_setting($setting)
      $settings = get_settings();
      $exists = 0;
      foreach ($settings as $element=>$key)
      if ($setting == $element)
      $exists = 1;


      if (!$exists)
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('INSERT INTO settings (name, value) VALUES (:name, :value)');
      $query->bindValue(':name', $setting, PDO::PARAM_STR);
      $query->bindValue(':value', '1', PDO::PARAM_STR);
      $query->execute();
      else
      echo "Setting already exists<br>";



      //Deletes responses from the database, takes the "find" string as input
      function del_settings($delete)
      $db = new PDO('sqlite:db.sqlite');
      foreach ($delete as $setting)
      $query = $db->prepare('DELETE FROM settings WHERE name=:setting');
      $query->bindValue(':setting', $setting, PDO::PARAM_STR);
      $query->execute();


      //Updates the config, takes an array of config paramaters with the element name being the paramter and the value being the value
      function update_config($config)
      $db = new PDO('sqlite:db.sqlite');
      foreach ($config as $name=>$value)
      if ($value[0] != "*")
      $query = $db->prepare('UPDATE config SET value=:value WHERE name=:name');
      $query->bindValue(':name', $name, PDO::PARAM_STR);
      $query->bindValue(':value', $value, PDO::PARAM_STR);
      $query->execute();



      //Display the setup form
      function disp_setup()
      $setup = <<<'EOSETUP'
      <form name="setup" method="post" action="">
      <table align="center" style="width: 50%;">
      <tr>
      <td>Panel username:</td>
      <td><input type="text" style="width: 100%;" name="user" placeholder="Panel username" required></td>
      </tr>
      <tr>
      <td>Panel password:</td>
      <td><input type="password" style="width: 100%;" name="pass" placeholder="Panel password" required></td>
      </tr>
      <tr>
      <td>GroupMe API token:</td>
      <td><input type="text" style="width: 100%;" name="apitoken" placeholder="Your GroupMe API token" required></td>
      </tr>
      <tr>
      <td>GroupMe Bot token:</td>
      <td><input type="text" style="width: 100%;" name="bottoken" placeholder="Your GroupMe Bot token" required></td>
      </tr>
      <tr>
      <td>WeatherUnderground API token:</td>
      <td><input type="text" style="width: 100%;" name="wutoken" placeholder="Your WeatherUnderground API token" value=""></td>
      </tr>
      <tr>
      <td>WeatherUnderground location code:</td>
      <td><input type="text" style="width: 100%;" name="wuloc" placeholder="Your WeatherUnderground location code" value=""></td>
      </tr>
      <tr>
      <td>Logging, check to enable</td>
      <td><input type="checkbox" style="width: 100%;" name="log" value="1" checked required></td>
      </tr>
      <tr>
      <td colspan="3"><input type="submit" value="Initialize"></td>
      </tr>
      </table>
      </form>
      EOSETUP;
      echo $setup;

      //Display the login
      function disp_login()
      $login = <<<'EOLOGIN'
      <form name="login" method="post" action="">
      <table align="center" style="width: 50%;">
      <tr>
      <td>Username:</td>
      <td><input type="text" style="width: 100%;" name="username" placeholder="Panel username" required></td>
      </tr>
      <tr>
      <td>Password:</td>
      <td><input type="password" style="width: 100%;" name="password" placeholder="Panel password" required></td>
      </tr>
      <tr>
      <td colspan="3"><input type="submit" value="Login"></td>
      </tr>
      </table>
      </form>
      EOLOGIN;
      echo $login;



      index.php:



      <!DOCTYPE html>
      <html>
      <head>
      <style>
      body
      background: url("https://picload.org/image/dadcrgpl/background.png");
      background-repeat: repeat-y;
      background-size: cover;
      color: white;
      margin: 0;
      padding: 0;
      left: 0;
      right: 0;
      position: absolute;
      font-size: 16px;
      text-align: center;
      font-family: "Lucida Console", Monaco, monospace;

      form
      border: 0;
      margin: 0;

      ul
      list-style-type: none;
      margin: 0;
      padding: 0;
      overflow: hidden;

      li
      float: left;
      display: block;

      summary
      background: rgba(255, 0, 0, .1);
      text-align: left;;
      font-size: 18px;

      table
      max-width: 100%;
      border-spacing: 0;
      text-align: left;
      font-size: 16px;

      tr
      max-width: 100%;

      th, td
      height: 100%;
      padding: 10px;
      overflow-x: hidden;
      vertical-align: middle;

      tr:nth-child(even)
      background-color: rgba(255, 255, 255, 0.50);

      tr:nth-child(odd)
      background-color: rgba(255, 255, 255, 0.25);

      input
      border: 0;
      box-sizing: border-box;
      color: white;
      text-indent: 0px;
      font-size: 16px;
      background: rgba(0, 0, 0, 0);
      font-family: "Lucida Console", Monaco, monospace;

      </style>
      <title>PHP GroupMe Bot</title>
      </head>
      <body>
      <?php
      header('Content-type: text/html; charset=utf-8');
      ini_set('display_errors', 1);
      ini_set('session.save_path', getcwd());
      error_reporting(-1);
      include 'functions.php';
      session_start();
      if (file_exists('db.sqlite'))
      if (isset($_SESSION['username']))
      if (isset($_POST['logout']))
      session_destroy();
      header("Refresh:1");

      if (!empty($_POST['add_admin_name']) && !empty($_POST['add_admin_pass']))
      add_admin($_POST['add_admin_name'], $_POST['add_admin_pass']);

      if (isset($_POST['delete_admin']))
      delete_admin($_POST['delete_admin']);

      if (isset($_POST['change_admin_pass']))
      change_admin_pass($_POST['change_admin_pass']);

      if (isset($_POST['config']))
      update_config($_POST['config']);

      if (isset($_POST['find']) && isset($_POST['respond']) && !empty($_POST['find']) && !empty($_POST['respond']))
      add_response($_POST['find'], $_POST['respond']);

      if (isset($_POST['delete']))
      del_responses($_POST['delete']);

      if (isset($_POST['users']))
      if (isset($_POST['admins']))
      update_admins($_POST['admins']);
      else
      delete_admins();

      if (isset($_POST['ignored']))
      update_ignored($_POST['ignored']);
      else
      delete_ignored();


      if (isset($_POST['settings']))
      update_settings($_POST['settings']);

      if (isset($_POST['new_setting']) && !empty($_POST['new_setting']))
      add_setting($_POST['new_setting']);

      if (isset($_POST['del_settings']) && !empty($_POST['del_settings']))
      del_settings($_POST['del_settings']);

      if (isset($_POST['send']) && !empty($_POST['send']))
      send($_POST['send']);
      ?>
      <div style="align: right; height: 5vh; background: rgba(0, 0, 0, .5);">
      <ul>
      <?php
      $username = $_SESSION['username'];
      echo "<li>$username Logged in</li>";
      ?>
      <form name="logout" method="post" action="">
      <li><input type="hidden" name="logout" value="logout"></li>
      <input style="float: right;" type="submit" value="Log Out">
      </form>
      </div>
      <div style="overflow-y: scroll; height: 90vh">
      <details>
      <summary>Panel</summary>
      <form name="panel" method="post" action="">
      <table align="center">
      <tr>
      <th>Panel Admins</th>
      <th>Delete</th>
      <th>Change Password</th>
      </tr>
      <?php
      $admins = get_panel_admins();
      foreach ($admins as $element)
      $name = $element;
      echo "<tr>";
      echo "<td>$name</td>";
      echo "<td><input type="checkbox" name="delete_admin" value="$name"></td>";
      echo "<td><input type="password" name="change_admin_pass[$name]" placeholder="Password"></td>";
      echo "</tr>";
      ?>
      <tr>
      <td><input type="text" name="add_admin_name" placeholder="Username"></td>
      <td colspan="2"><input type="password" name="add_admin_pass" placeholder="Password"></td>
      <tr>
      <th colspan="3"><input type="submit" value="Update"></th>
      </tr>
      </table>
      </form>
      </details>
      <details>
      <summary>Config</summary>
      <form name="config" method="post" action="">
      <table align="center">
      <tr>
      <th>Setting</th>
      <th>Value</th>
      <th>New Value</th>
      </tr>
      <?php
      $config = get_config();
      foreach ($config as $element)
      $name = $element['name'];
      $value = $element['value'];
      echo "<tr>";
      echo "<td>$name</td>";
      if (stripos($name, 'token') !== FALSE)
      $value = str_repeat('*', strlen($value) - 4) . substr($value, -4);
      echo "<td>$value</td>";
      echo "<td><input type="text" name="config[$name]" value="$value"></td>";
      else
      echo "<td>$value</td>";
      echo "<td><input type="text" name="config[$name]" value="$value"></td>";

      echo "</tr>";
      ?>
      <tr>
      <th colspan="3"><input type="submit" value="Update"></th>
      </tr>
      </table>
      </form>
      </details>
      <details>
      <summary>Add</summary>
      <form name="add" method="post" action="">
      <h3>%n can be used to mention someone in a response</h3>
      <table align="center">
      <tr>
      <th><input type="text" name="find" placeholder="Text to find"></th>
      <th><input type="text" name="respond" placeholder="Text to respond with"></th>
      <th><input type="submit" value="Add"></th>
      </tr>
      </table>
      </form>
      </details>
      <details>
      <summary>Delete</summary>
      <form name="delete" method="post" action="">
      <table align="center">
      <tr>
      <th>Find</th>
      <th>Respond</th>
      <th>Delete</th>
      </tr>
      <?php
      $responses = get_responses();
      foreach ($responses as $element)
      $find = $element['find'];
      $respond = $element['respond'];
      echo "<tr>";
      echo "<td>$find</td>";
      echo "<td>$respond</td>";
      echo "<td><input type="checkbox" name="delete" value="$find"></td>";
      echo "</tr>";
      ?>
      <tr>
      <th colspan="3"><input type="submit" value="Remove"></th>
      </tr>
      </table>
      </form>
      </details>
      <details>
      <summary>Users</summary>
      <form name="Users" method="post" action="">
      <table align="center">
      <tr>
      <th>Name</th>
      <th>Admin</th>
      <th>Ignored</th>
      </tr>
      <?php
      $admins = get_admins();
      $ignored = get_ignored();
      $users = get_users();
      $i = 0;
      foreach ($users as $user)
      $name = htmlspecialchars($user["name"]);
      $userid = htmlspecialchars($user["userid"]);
      $avatar = $user["avatar"];
      echo "<tr>";
      echo "<td style="text-align: left;"><img src="$avatar" style="width:50px; height:50px; vertical-align: middle;">$name ($userid)</td>";
      if (in_array($users[$i]['userid'], $admins))
      echo "<td><input type="checkbox" name="admins" value="$userid" checked></td>";
      else
      echo "<td><input type="checkbox" name="admins" value="$userid"></td>";

      if (in_array($users[$i]['userid'], $ignored))
      echo "<td><input type="checkbox" name="ignored" value="$userid" checked></td>";
      else
      echo "<td><input type="checkbox" name="ignored" value="$userid"></td>";

      echo "</tr>";
      $i++;
      ?>
      <tr>
      <th colspan="3"><input type="submit" value="Update"></th>
      </tr>
      </table>
      <input type="hidden" name="users" value="1">
      </form>
      </details>
      <details>
      <summary>Settings</summary>
      <form name="settings" method="post" action="">
      <table align="center">
      <tr>
      <th>Name</th>
      <th>State</th>
      <th>Delete</th>
      </tr>
      <?php
      $settings = get_settings();
      foreach ($settings as $element=>$key)
      $name = $element;
      $value = $key;
      echo "<tr>";
      echo "<td>$name</td>";
      if ($value)
      echo "<td><input type="checkbox" name="settings" value="$name" checked></td>";
      else
      echo "<td><input type="checkbox" name="settings" value="$name"></td>";

      echo "<td><input type="checkbox" name="del_settings" value="$name"></td>";
      echo "</tr>";
      ?>
      <tr>
      <td>Add setting</td>
      <td colspan="2"><input type="text" name="new_setting" placeholder="Name for new setting"></td>
      </tr>
      <tr>
      <th colspan="3"><input type="submit" value="Update"></th>
      </tr>
      </table>
      <input type="hidden" name="settings" value="1">
      </form>
      </details>
      <details>
      <summary>Log</summary>
      <table style="width: 100%;">
      <?php
      $log = get_log();
      foreach ($log as $element)
      $timestamp = date("Y-m-d@H:i:s", $element['timestamp']);
      $entry = htmlspecialchars($element['entry']);
      echo "<tr>";
      echo "<td>$timestamp</td>";
      echo "<td>$entry</td>";
      echo "</tr>";
      ?>
      </table>
      </details>
      </div>
      <form name="send" method="post" action="">
      <table style="width: 100%; position: fixed; bottom: 0; height: 5vh">
      <tr>
      <th><input type="text" name="send" placeholder="Message to send"></th>
      </tr>
      </table>
      <input type="submit" value="Send" style="display: none">
      </form>
      <?php
      else
      disp_login();
      if (isset($_POST['username']) && isset($_POST['password']))
      $db = new PDO('sqlite:db.sqlite');
      $username = strtolower($_POST['username']);
      $password = $_POST['password'];
      $query = $db->prepare('SELECT password FROM auth WHERE username=:username');
      $query->bindValue(':username', $username, PDO::PARAM_STR);
      $query->execute();
      $hashed = $query->fetch(PDO::FETCH_COLUMN, 0);
      if (password_verify($password, $hashed))
      echo "Logging in...";
      $_SESSION['username'] = $username;
      header("Refresh:1");
      else
      echo "Incorrect password!";



      else if (is_writeable('./'))
      if (!empty($_POST) && initdb())
      $db = new PDO('sqlite:db.sqlite');
      $config = ['apitoken', 'bottoken', 'wutoken', 'wuloc'];
      $settings = ['litecoin', 'bitcoin', 'ethereum'];
      foreach($config as $variable)
      $statement = $db->prepare('INSERT INTO config (name, value) VALUES (:name, :value)');
      $statement->bindValue(':name', $variable, PDO::PARAM_STR);
      $statement->bindValue(':value', $_POST[$variable], PDO::PARAM_STR);
      $statement->execute();

      if ($_POST['log'])
      $db->exec("INSERT INTO config (name, value) VALUES ('log', '1')");
      else
      $db->exec("INSERT INTO config (name, value) VALUES ('log', '1')");

      if ((isset($_POST['wutoken'])) && isset($_POST['wuloc']))
      $db->exec("INSERT INTO settings (name, value) VALUES ('weather', '1')");
      else
      $db->exec("INSERT INTO settings (name, value) VALUES ('weather', '0')");

      $db->exec("INSERT INTO settings (name, value) VALUES ('lights', '0')");
      $db->exec("INSERT INTO responses (find, respond) VALUES ('test', 'It works!')");
      add_admin($_POST['user'], $_POST['pass']);
      foreach($settings as $variable)
      $statement = $db->prepare('INSERT INTO settings (name, value) VALUES (:name, :value)');
      $statement->bindValue(':name', $variable, PDO::PARAM_STR);
      $statement->bindValue(':value', '1', PDO::PARAM_STR);
      $statement->execute();

      file_put_contents('.htaccess', "<Files "db.sqlite">nDeny From Alln</Files>n<Files "sess*">nDeny From Alln</Files>");
      header("Refresh:1");

      disp_setup();
      else
      echo "Working directory is not writeable, either chown it to the webserver user and group or allow write permissions to everyone (insecure!)";
      ?>
      </body>
      </html>






      share|improve this question











      I made a lot of updates to my GroupMe bot, now it uses sqlite and has a web panel. I'm wondering if there are any bad coding techniques used and more importantly if there are any security issues with it.
      https://github.com/desultory/GroupMe-Bot



      bot.php:



      <?php
      //Includes all functions and parses the post data into appropriate variables
      include 'functions.php';
      include 'lights.php';

      $callback = json_decode(file_get_contents('php://input'));
      $attachments = $callback->attachments;
      $avatar = $callback->avatar_url;
      $name = $callback->name;
      $type = $callback->sender_type;
      $text = $callback->text;
      $userid = $callback->user_id;

      $admins = get_admins();
      $ignored = get_ignored();
      $settings = get_settings();

      //If logging is enabled in the config, this logs the chat to the database
      logging($userid, $name, $text);

      //Only handles messages from users to prevent infinite loops
      if ($type == 'user' && !in_array($userid, $ignored) && $text[0] != '/')
      //Basic response is a simple response to a found phrase
      basic_response($text, $name, $userid);
      //If the Weather Underground API token and location are set and weather has been enabled, this will return a forecast if someone says "weather"
      if ($settings['weather'])
      weather_response($text);

      //If anyone says "bitcoin" and the bitcoin setting is enabled, this will return the price in USD
      if ($settings['bitcoin'])
      btc_response($text);

      //If anyone says "ethereum" and the ethereum setting is enabled, this will return the price in USD and BTC
      if ($settings['ethereum'])
      eth_response($text);

      //If anyone says "litecoin" and the litecoin setting is enabled, this will return the price in USD and BTC
      if ($settings['litecoin'])
      ltc_response($text);

      if ($settings['lights'])
      blink($ip, $pins, "50", "20");


      if (in_array($userid, $admins) && $type == 'user' && $text == '/config')



      functions.php:



      <?php
      //Writes the contents of a variable to a text file for debugging purposes
      function debugvar($variable)
      file_put_contents('debug.txt', print_r($variable, true));

      //Initialize the database
      function initdb()
      $db = new PDO('sqlite:db.sqlite');
      $dbcmds = ['CREATE TABLE IF NOT EXISTS config(
      name TEXT NOT NULL,
      value TEXT NOT NULL
      )',
      'CREATE TABLE IF NOT EXISTS settings(
      name TEXT NOT NULL,
      value INTEGER NOT NULL
      )',
      'CREATE TABLE IF NOT EXISTS responses(
      find TEXT NOT NULL,
      respond TEXT NOT NULL
      )',
      'CREATE TABLE IF NOT EXISTS users(
      name TEXT NOT NULL,
      userid TEXT NOT NULL,
      admin INTEGER,
      ignored INTEGER
      )',
      'CREATE TABLE IF NOT EXISTS auth(
      username TEXT NOT NULL,
      password TEXT NOT NULL
      )',
      'CREATE TABLE IF NOT EXISTS log(
      entry TEXT NOT NULL,
      timestamp INTEGER NOT NULL
      )',
      ];
      foreach ($dbcmds as $cmd)
      $db->exec($cmd);

      $clean = 1;
      foreach ($db->errorInfo() as $error)
      if ($error != 0)
      $clean = $error;


      return $clean;

      //Gets the specified config variable value from the database
      function get_config_var($parameter)
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('SELECT value FROM config WHERE name=:name');
      $query->bindValue(':name', $parameter, PDO::PARAM_STR);
      $query->execute();
      $result = $query->fetch(PDO::FETCH_ASSOC);
      return $result['value'];

      //Returns panel admins as an array
      function get_panel_admins()
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('SELECT username FROM auth');
      $query->execute();
      $result = $query->fetchAll(PDO::FETCH_COLUMN, 0);
      return $result;

      //Adds admins listed in array
      function add_admin($user, $pass)
      $db = new PDO('sqlite:db.sqlite');
      $admins = get_panel_admins();
      $username = strtolower($user);
      $password = password_hash($pass, PASSWORD_DEFAULT);
      if (!in_array($username, $admins))
      $query = $db->prepare('INSERT INTO auth (username, password) VALUES (:username, :password)');
      $query->bindValue(':username', $username, PDO::PARAM_STR);
      $query->bindValue(':password', $password, PDO::PARAM_STR);
      $query->execute();
      else
      echo "Admin already exists";


      //Changes an admin password to the specified password
      function change_admin_pass($users)
      $db = new PDO('sqlite:db.sqlite');
      foreach ($users as $name=>$pass)
      if (!empty($pass))
      $username = strtolower($name);
      $password = password_hash($pass, PASSWORD_DEFAULT);
      $query = $db->prepare('UPDATE auth set password=:password WHERE username=:username');
      $query->bindValue(':username', $username, PDO::PARAM_STR);
      $query->bindValue(':password', $password, PDO::PARAM_STR);
      $query->execute();



      //Deletes admins listed in array
      function delete_admin($delete)
      $db = new PDO('sqlite:db.sqlite');
      foreach ($delete as $name)
      $query = $db->prepare('SELECT count(username) FROM auth');
      $query->execute();
      $count = $query->fetch();
      $count = $count[0];
      if ($count > '1')
      $username = strtolower($name);
      $query = $db->prepare('DELETE FROM auth WHERE username=:name');
      $query->bindValue(':name', $username, PDO::PARAM_STR);
      $query->execute();
      else
      echo "Cannot delete last admin";



      //Returns the responses as an array
      function get_responses()
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('SELECT find,respond FROM responses');
      $query->execute();
      return $query->fetchAll();

      //Returns the config as an array
      function get_config()
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('SELECT name,value FROM config');
      $query->execute();
      return $query->fetchAll();

      //Returns the chat log
      function get_log()
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('SELECT entry,timestamp FROM log');
      $query->execute();
      return $query->fetchAll();

      //Returns the admins as an array
      function get_admins()
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('SELECT userid FROM users WHERE admin=1');
      $query->execute();
      return $query->fetchAll(PDO::FETCH_COLUMN, 0);

      //Returns the ignored users as an array
      function get_ignored()
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('SELECT userid FROM users WHERE ignored=1');
      $query->execute();
      return $query->fetchAll(PDO::FETCH_COLUMN, 0);

      //Returns the settings as an array
      function get_settings()
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('SELECT name,value FROM settings');
      $query->execute();
      $result = $query->fetchAll();
      foreach ($result as $setting)
      $settings[$setting[0]] = $setting[1];

      return $settings;

      //Logs all chat to the database
      function logging($userid, $name, $text)
      $db = new PDO('sqlite:db.sqlite');
      if (get_config_var('log'))
      $entry = "$name($userid): $text";
      $statement = $db->prepare('INSERT INTO log (entry, timestamp) VALUES (:entry, :timestamp)');
      $statement->bindValue(':entry', $entry, PDO::PARAM_STR);
      $statement->bindValue(':timestamp', time(), PDO::PARAM_STR);
      $statement->execute();



      //Basic response (no images)
      function basic_response($text, $name, $userid)
      $responses = get_responses();
      foreach ($responses as $element)
      if (stripos($text, $element[0]) !== FALSE)
      $message = $element[1];
      $message = str_replace('%u', $userid, $message);
      if (stripos($message, '%n') !== FALSE)
      $message = str_replace('%n', $name, $message);
      mention($message, $name);
      else
      send($message);




      //WUnderground response
      function weather_response($text)
      $wutoken = get_config_var('wutoken');
      $wuloc = get_config_var('wuloc');
      if (stripos($text, 'weather') !== FALSE)
      if (isset($wutoken) && isset($wuloc))
      $rawweather = json_decode(curl_get("https://api.wunderground.com/api/$wutoken/conditions/q/$wuloc.json"));
      $temperature = $rawweather->current_observation->feelslike_string;
      $weather = $rawweather->current_observation->weather;
      $icon = $rawweather->current_observation->icon_url;
      $forecast = "The weather is $weather with a temperature of $temperature";
      send_img($forecast, $icon);
      else
      send('WUnderground token and location are not set');



      //Bitcoin value response
      function btc_response($text)
      if (stripos($text, 'bitcoin') !== FALSE)
      $pricedata = json_decode(curl_get("https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=USD"));
      $usdprice = $pricedata->USD;
      $message = "Bitcoin is worth $$usdprice";
      $btclogo = 'https://files.coinmarketcap.com/static/img/coins/32x32/bitcoin.png';
      send_img($message, $btclogo);


      //Ethereum value response
      function eth_response($text)
      if (stripos($text, 'ethereum') !== FALSE)
      $pricedata = json_decode(curl_get("https://min-api.cryptocompare.com/data/price?fsym=ETH&tsyms=BTC,USD"));
      $usdprice = $pricedata->USD;
      $btcprice = $pricedata->BTC;
      $message = "Ethereum is worth $$usdprice and $btcprice Bitcoin";
      $ethlogo = 'https://files.coinmarketcap.com/static/img/coins/32x32/ethereum.png';
      send_img($message, $ethlogo);


      //Litecoin value response
      function ltc_response($text)
      if (stripos($text, 'litecoin') !== FALSE)
      $pricedata = json_decode(curl_get("https://min-api.cryptocompare.com/data/price?fsym=LTC&tsyms=BTC,USD"));
      $usdprice = $pricedata->USD;
      $btcprice = $pricedata->BTC;
      $message = "Litecoin is worth $$usdprice and $btcprice Bitcoin";
      $ltclogo = 'https://files.coinmarketcap.com/static/img/coins/32x32/litecoin.png';
      send_img($message, $ltclogo);


      //Curl get function, takes url and returns the get response
      function curl_get($url)
      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, "$url");
      curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
      $get = curl_exec($ch);
      curl_close($ch);
      return $get;

      //Curl post to groupme, takes the postfields and posts to the groupme bot api
      function curl_post($postfields)
      $ch = curl_init();
      curl_setopt($ch, CURLOPT_URL, 'https://api.groupme.com/v3/bots/post');
      curl_setopt($ch, CURLOPT_POSTFIELDS, $postfields);
      curl_exec($ch);
      curl_close($ch);

      //Send message function, takes a message as input and posts to GroupMe
      function send($message)
      $bottoken = get_config_var('bottoken');
      $postdata = [
      'bot_id' => $bottoken,
      'text' => $message
      ];
      curl_post(http_build_query($postdata));

      //Send image function, takes message and img url as inputs and posts to GroupMe
      function send_img($message, $image)
      $bottoken = get_config_var('bottoken');
      $attachments = [
      'type' => 'image',
      'url' => $image
      ];
      $postdata = [
      'bot_id' => $bottoken,
      'text' => $message,
      'attachments' => [$attachments]
      ];
      curl_post(json_encode($postdata));

      //Mention function, takes a message and name as inputs and posts to GroupMe
      function mention($message, $name)
      $bottoken = get_config_var('bottoken');
      $loci = [
      stripos($message, $name),
      strlen($name)
      ];
      $attachments = [
      'loci' => [$loci],
      'type' => 'mentions',
      'user_ids' => [get_user_id($name)]
      ];
      $postdata = [
      'bot_id' => $bottoken,
      'text' => $message,
      'attachments' => [$attachments]
      ];
      curl_post(json_encode($postdata));

      //Get bot group function, returns the group id of the bot
      function get_bot_group()
      $apitoken = get_config_var('apitoken');
      $bottoken = get_config_var('bottoken');
      $bots = json_decode(curl_get("https://api.groupme.com/v3/bots?token=$apitoken"));
      foreach($bots->response as $element)
      if ($element->bot_id == $bottoken)
      return $element->group_id;



      //Get user id function, takes a name as input and returns the user id
      function get_user_id($name)
      $apitoken = get_config_var('apitoken');
      $user_id = 'No member with that name found';
      $groupid = get_bot_group();
      $groups = json_decode(curl_get("https://api.groupme.com/v3/groups?token=$apitoken"));
      foreach($groups->response as $element)
      if ($element->id == $groupid)
      foreach($element->members as $member)
      if (stripos($member->nickname, $name) !== FALSE)
      $user_id = $member->user_id;




      return $user_id;

      //Get name function, takes a user id as input and returns the name associated with that user id
      function get_name($userid)
      $apitoken = get_config_var('apitoken');
      $name = 'Invalid userid';
      $groupid = get_bot_group();
      $groups = json_decode(curl_get("https://api.groupme.com/v3/groups?token=$apitoken"));
      foreach($groups->response as $element)
      if ($element->id == $groupid)
      foreach($element->members as $member)
      if ($userid == $member->user_id)
      $name = $member->nickname;




      return $name;

      //Get users function, gets user information from the groupme api, adds it to the database, and returns it as an array
      function get_users()
      $apitoken = get_config_var('apitoken');
      $groupid = get_bot_group();
      $groups = json_decode(curl_get("https://api.groupme.com/v3/groups?token=$apitoken"));
      $index = 0;
      $db = new PDO('sqlite:db.sqlite');
      foreach($groups->response as $element)
      if ($element->id == $groupid)
      foreach($element->members as $member)
      $userid = $member->user_id;
      $name = $member->nickname;
      $avatar = $member->image_url;
      $query = $db->prepare('SELECT userid FROM users WHERE userid=:userid');
      $query->bindValue('userid', $userid, PDO::PARAM_STR);
      $query->execute();
      $result = $query->fetch(PDO::FETCH_ASSOC);
      if (isset($result['userid']))
      $query = $db->prepare('UPDATE users SET name=:name WHERE userid=:userid');
      $query->bindValue(':name', $name, PDO::PARAM_STR);
      $query->bindValue(':userid', $userid, PDO::PARAM_STR);
      $query->execute();
      else
      $query = $db->prepare('INSERT INTO users (name, userid) VALUES (:name, :userid)');
      $query->bindValue(':name', $name, PDO::PARAM_STR);
      $query->bindValue(':userid', $userid, PDO::PARAM_STR);
      $query->execute();

      $members[$index] = [
      "userid" => $userid,
      "name" => $name,
      "avatar" => $avatar
      ];
      $index++;



      return $members;

      //Adds a response to the database, uses input find and respond where find is the text that is searched for and respond is the text that is retrned
      function add_response($find, $respond)
      $responses = get_responses();
      $exists = 0;
      foreach ($responses as $element)
      if (stripos($element[0], $find) !== FALSE
      if (!$exists)
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('INSERT INTO responses (find, respond) VALUES (:find, :respond)');
      $query->bindValue(':find', $find, PDO::PARAM_STR);
      $query->bindValue(':respond', $respond, PDO::PARAM_STR);
      $query->execute();
      else
      echo "Similar find already exists<br>";



      //Deletes responses from the database, takes the "find" string as input
      function del_responses($delete)
      $db = new PDO('sqlite:db.sqlite');
      foreach ($delete as $find)
      $query = $db->prepare('DELETE FROM responses WHERE find=:find');
      $query->bindValue(':find', $find, PDO::PARAM_STR);
      $query->execute();


      //Deletes all admins from the database
      function delete_admins()
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('UPDATE users SET admin = 0');
      $query->execute();

      //Updates the admins by deleting all of them and then adding the specified userids
      function update_admins($admins)
      delete_admins();
      $db = new PDO('sqlite:db.sqlite');
      foreach ($admins as $element)
      $query = $db->prepare('UPDATE users SET admin=:admin WHERE userid=:userid');
      $query->bindValue(':userid', $element, PDO::PARAM_STR);
      $query->bindValue(':admin', '1', PDO::PARAM_STR);
      $query->execute();


      //Deletes all ignored users from the database
      function delete_ignored()
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('UPDATE users SET ignored = 0');
      $query->execute();

      //Updates the users by deleting all of them and then adding the specified userids
      function update_ignored($ignored)
      delete_ignored();
      $db = new PDO('sqlite:db.sqlite');
      foreach ($ignored as $element)
      $query = $db->prepare('UPDATE users SET ignored=:ignored WHERE userid=:userid');
      $query->bindValue(':userid', $element, PDO::PARAM_STR);
      $query->bindValue(':ignored', '1', PDO::PARAM_STR);
      $query->execute();


      //Resets all settings in the database
      function reset_settings()
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('UPDATE settings SET value = 0');
      $query->execute();

      //Updates the settings by restting all of the settings and then enabling the specified ones
      function update_settings($settings)
      reset_settings();
      $db = new PDO('sqlite:db.sqlite');
      foreach ($settings as $element)
      $query = $db->prepare('UPDATE settings SET value=:value WHERE name=:name');
      $query->bindValue(':name', $element, PDO::PARAM_STR);
      $query->bindValue(':value', '1', PDO::PARAM_STR);
      $query->execute();


      //Adds the specified setting to the array if it doesn't already exist
      function add_setting($setting)
      $settings = get_settings();
      $exists = 0;
      foreach ($settings as $element=>$key)
      if ($setting == $element)
      $exists = 1;


      if (!$exists)
      $db = new PDO('sqlite:db.sqlite');
      $query = $db->prepare('INSERT INTO settings (name, value) VALUES (:name, :value)');
      $query->bindValue(':name', $setting, PDO::PARAM_STR);
      $query->bindValue(':value', '1', PDO::PARAM_STR);
      $query->execute();
      else
      echo "Setting already exists<br>";



      //Deletes responses from the database, takes the "find" string as input
      function del_settings($delete)
      $db = new PDO('sqlite:db.sqlite');
      foreach ($delete as $setting)
      $query = $db->prepare('DELETE FROM settings WHERE name=:setting');
      $query->bindValue(':setting', $setting, PDO::PARAM_STR);
      $query->execute();


      //Updates the config, takes an array of config paramaters with the element name being the paramter and the value being the value
      function update_config($config)
      $db = new PDO('sqlite:db.sqlite');
      foreach ($config as $name=>$value)
      if ($value[0] != "*")
      $query = $db->prepare('UPDATE config SET value=:value WHERE name=:name');
      $query->bindValue(':name', $name, PDO::PARAM_STR);
      $query->bindValue(':value', $value, PDO::PARAM_STR);
      $query->execute();



      //Display the setup form
      function disp_setup()
      $setup = <<<'EOSETUP'
      <form name="setup" method="post" action="">
      <table align="center" style="width: 50%;">
      <tr>
      <td>Panel username:</td>
      <td><input type="text" style="width: 100%;" name="user" placeholder="Panel username" required></td>
      </tr>
      <tr>
      <td>Panel password:</td>
      <td><input type="password" style="width: 100%;" name="pass" placeholder="Panel password" required></td>
      </tr>
      <tr>
      <td>GroupMe API token:</td>
      <td><input type="text" style="width: 100%;" name="apitoken" placeholder="Your GroupMe API token" required></td>
      </tr>
      <tr>
      <td>GroupMe Bot token:</td>
      <td><input type="text" style="width: 100%;" name="bottoken" placeholder="Your GroupMe Bot token" required></td>
      </tr>
      <tr>
      <td>WeatherUnderground API token:</td>
      <td><input type="text" style="width: 100%;" name="wutoken" placeholder="Your WeatherUnderground API token" value=""></td>
      </tr>
      <tr>
      <td>WeatherUnderground location code:</td>
      <td><input type="text" style="width: 100%;" name="wuloc" placeholder="Your WeatherUnderground location code" value=""></td>
      </tr>
      <tr>
      <td>Logging, check to enable</td>
      <td><input type="checkbox" style="width: 100%;" name="log" value="1" checked required></td>
      </tr>
      <tr>
      <td colspan="3"><input type="submit" value="Initialize"></td>
      </tr>
      </table>
      </form>
      EOSETUP;
      echo $setup;

      //Display the login
      function disp_login()
      $login = <<<'EOLOGIN'
      <form name="login" method="post" action="">
      <table align="center" style="width: 50%;">
      <tr>
      <td>Username:</td>
      <td><input type="text" style="width: 100%;" name="username" placeholder="Panel username" required></td>
      </tr>
      <tr>
      <td>Password:</td>
      <td><input type="password" style="width: 100%;" name="password" placeholder="Panel password" required></td>
      </tr>
      <tr>
      <td colspan="3"><input type="submit" value="Login"></td>
      </tr>
      </table>
      </form>
      EOLOGIN;
      echo $login;



      index.php:



      <!DOCTYPE html>
      <html>
      <head>
      <style>
      body
      background: url("https://picload.org/image/dadcrgpl/background.png");
      background-repeat: repeat-y;
      background-size: cover;
      color: white;
      margin: 0;
      padding: 0;
      left: 0;
      right: 0;
      position: absolute;
      font-size: 16px;
      text-align: center;
      font-family: "Lucida Console", Monaco, monospace;

      form
      border: 0;
      margin: 0;

      ul
      list-style-type: none;
      margin: 0;
      padding: 0;
      overflow: hidden;

      li
      float: left;
      display: block;

      summary
      background: rgba(255, 0, 0, .1);
      text-align: left;;
      font-size: 18px;

      table
      max-width: 100%;
      border-spacing: 0;
      text-align: left;
      font-size: 16px;

      tr
      max-width: 100%;

      th, td
      height: 100%;
      padding: 10px;
      overflow-x: hidden;
      vertical-align: middle;

      tr:nth-child(even)
      background-color: rgba(255, 255, 255, 0.50);

      tr:nth-child(odd)
      background-color: rgba(255, 255, 255, 0.25);

      input
      border: 0;
      box-sizing: border-box;
      color: white;
      text-indent: 0px;
      font-size: 16px;
      background: rgba(0, 0, 0, 0);
      font-family: "Lucida Console", Monaco, monospace;

      </style>
      <title>PHP GroupMe Bot</title>
      </head>
      <body>
      <?php
      header('Content-type: text/html; charset=utf-8');
      ini_set('display_errors', 1);
      ini_set('session.save_path', getcwd());
      error_reporting(-1);
      include 'functions.php';
      session_start();
      if (file_exists('db.sqlite'))
      if (isset($_SESSION['username']))
      if (isset($_POST['logout']))
      session_destroy();
      header("Refresh:1");

      if (!empty($_POST['add_admin_name']) && !empty($_POST['add_admin_pass']))
      add_admin($_POST['add_admin_name'], $_POST['add_admin_pass']);

      if (isset($_POST['delete_admin']))
      delete_admin($_POST['delete_admin']);

      if (isset($_POST['change_admin_pass']))
      change_admin_pass($_POST['change_admin_pass']);

      if (isset($_POST['config']))
      update_config($_POST['config']);

      if (isset($_POST['find']) && isset($_POST['respond']) && !empty($_POST['find']) && !empty($_POST['respond']))
      add_response($_POST['find'], $_POST['respond']);

      if (isset($_POST['delete']))
      del_responses($_POST['delete']);

      if (isset($_POST['users']))
      if (isset($_POST['admins']))
      update_admins($_POST['admins']);
      else
      delete_admins();

      if (isset($_POST['ignored']))
      update_ignored($_POST['ignored']);
      else
      delete_ignored();


      if (isset($_POST['settings']))
      update_settings($_POST['settings']);

      if (isset($_POST['new_setting']) && !empty($_POST['new_setting']))
      add_setting($_POST['new_setting']);

      if (isset($_POST['del_settings']) && !empty($_POST['del_settings']))
      del_settings($_POST['del_settings']);

      if (isset($_POST['send']) && !empty($_POST['send']))
      send($_POST['send']);
      ?>
      <div style="align: right; height: 5vh; background: rgba(0, 0, 0, .5);">
      <ul>
      <?php
      $username = $_SESSION['username'];
      echo "<li>$username Logged in</li>";
      ?>
      <form name="logout" method="post" action="">
      <li><input type="hidden" name="logout" value="logout"></li>
      <input style="float: right;" type="submit" value="Log Out">
      </form>
      </div>
      <div style="overflow-y: scroll; height: 90vh">
      <details>
      <summary>Panel</summary>
      <form name="panel" method="post" action="">
      <table align="center">
      <tr>
      <th>Panel Admins</th>
      <th>Delete</th>
      <th>Change Password</th>
      </tr>
      <?php
      $admins = get_panel_admins();
      foreach ($admins as $element)
      $name = $element;
      echo "<tr>";
      echo "<td>$name</td>";
      echo "<td><input type="checkbox" name="delete_admin" value="$name"></td>";
      echo "<td><input type="password" name="change_admin_pass[$name]" placeholder="Password"></td>";
      echo "</tr>";
      ?>
      <tr>
      <td><input type="text" name="add_admin_name" placeholder="Username"></td>
      <td colspan="2"><input type="password" name="add_admin_pass" placeholder="Password"></td>
      <tr>
      <th colspan="3"><input type="submit" value="Update"></th>
      </tr>
      </table>
      </form>
      </details>
      <details>
      <summary>Config</summary>
      <form name="config" method="post" action="">
      <table align="center">
      <tr>
      <th>Setting</th>
      <th>Value</th>
      <th>New Value</th>
      </tr>
      <?php
      $config = get_config();
      foreach ($config as $element)
      $name = $element['name'];
      $value = $element['value'];
      echo "<tr>";
      echo "<td>$name</td>";
      if (stripos($name, 'token') !== FALSE)
      $value = str_repeat('*', strlen($value) - 4) . substr($value, -4);
      echo "<td>$value</td>";
      echo "<td><input type="text" name="config[$name]" value="$value"></td>";
      else
      echo "<td>$value</td>";
      echo "<td><input type="text" name="config[$name]" value="$value"></td>";

      echo "</tr>";
      ?>
      <tr>
      <th colspan="3"><input type="submit" value="Update"></th>
      </tr>
      </table>
      </form>
      </details>
      <details>
      <summary>Add</summary>
      <form name="add" method="post" action="">
      <h3>%n can be used to mention someone in a response</h3>
      <table align="center">
      <tr>
      <th><input type="text" name="find" placeholder="Text to find"></th>
      <th><input type="text" name="respond" placeholder="Text to respond with"></th>
      <th><input type="submit" value="Add"></th>
      </tr>
      </table>
      </form>
      </details>
      <details>
      <summary>Delete</summary>
      <form name="delete" method="post" action="">
      <table align="center">
      <tr>
      <th>Find</th>
      <th>Respond</th>
      <th>Delete</th>
      </tr>
      <?php
      $responses = get_responses();
      foreach ($responses as $element)
      $find = $element['find'];
      $respond = $element['respond'];
      echo "<tr>";
      echo "<td>$find</td>";
      echo "<td>$respond</td>";
      echo "<td><input type="checkbox" name="delete" value="$find"></td>";
      echo "</tr>";
      ?>
      <tr>
      <th colspan="3"><input type="submit" value="Remove"></th>
      </tr>
      </table>
      </form>
      </details>
      <details>
      <summary>Users</summary>
      <form name="Users" method="post" action="">
      <table align="center">
      <tr>
      <th>Name</th>
      <th>Admin</th>
      <th>Ignored</th>
      </tr>
      <?php
      $admins = get_admins();
      $ignored = get_ignored();
      $users = get_users();
      $i = 0;
      foreach ($users as $user)
      $name = htmlspecialchars($user["name"]);
      $userid = htmlspecialchars($user["userid"]);
      $avatar = $user["avatar"];
      echo "<tr>";
      echo "<td style="text-align: left;"><img src="$avatar" style="width:50px; height:50px; vertical-align: middle;">$name ($userid)</td>";
      if (in_array($users[$i]['userid'], $admins))
      echo "<td><input type="checkbox" name="admins" value="$userid" checked></td>";
      else
      echo "<td><input type="checkbox" name="admins" value="$userid"></td>";

      if (in_array($users[$i]['userid'], $ignored))
      echo "<td><input type="checkbox" name="ignored" value="$userid" checked></td>";
      else
      echo "<td><input type="checkbox" name="ignored" value="$userid"></td>";

      echo "</tr>";
      $i++;
      ?>
      <tr>
      <th colspan="3"><input type="submit" value="Update"></th>
      </tr>
      </table>
      <input type="hidden" name="users" value="1">
      </form>
      </details>
      <details>
      <summary>Settings</summary>
      <form name="settings" method="post" action="">
      <table align="center">
      <tr>
      <th>Name</th>
      <th>State</th>
      <th>Delete</th>
      </tr>
      <?php
      $settings = get_settings();
      foreach ($settings as $element=>$key)
      $name = $element;
      $value = $key;
      echo "<tr>";
      echo "<td>$name</td>";
      if ($value)
      echo "<td><input type="checkbox" name="settings" value="$name" checked></td>";
      else
      echo "<td><input type="checkbox" name="settings" value="$name"></td>";

      echo "<td><input type="checkbox" name="del_settings" value="$name"></td>";
      echo "</tr>";
      ?>
      <tr>
      <td>Add setting</td>
      <td colspan="2"><input type="text" name="new_setting" placeholder="Name for new setting"></td>
      </tr>
      <tr>
      <th colspan="3"><input type="submit" value="Update"></th>
      </tr>
      </table>
      <input type="hidden" name="settings" value="1">
      </form>
      </details>
      <details>
      <summary>Log</summary>
      <table style="width: 100%;">
      <?php
      $log = get_log();
      foreach ($log as $element)
      $timestamp = date("Y-m-d@H:i:s", $element['timestamp']);
      $entry = htmlspecialchars($element['entry']);
      echo "<tr>";
      echo "<td>$timestamp</td>";
      echo "<td>$entry</td>";
      echo "</tr>";
      ?>
      </table>
      </details>
      </div>
      <form name="send" method="post" action="">
      <table style="width: 100%; position: fixed; bottom: 0; height: 5vh">
      <tr>
      <th><input type="text" name="send" placeholder="Message to send"></th>
      </tr>
      </table>
      <input type="submit" value="Send" style="display: none">
      </form>
      <?php
      else
      disp_login();
      if (isset($_POST['username']) && isset($_POST['password']))
      $db = new PDO('sqlite:db.sqlite');
      $username = strtolower($_POST['username']);
      $password = $_POST['password'];
      $query = $db->prepare('SELECT password FROM auth WHERE username=:username');
      $query->bindValue(':username', $username, PDO::PARAM_STR);
      $query->execute();
      $hashed = $query->fetch(PDO::FETCH_COLUMN, 0);
      if (password_verify($password, $hashed))
      echo "Logging in...";
      $_SESSION['username'] = $username;
      header("Refresh:1");
      else
      echo "Incorrect password!";



      else if (is_writeable('./'))
      if (!empty($_POST) && initdb())
      $db = new PDO('sqlite:db.sqlite');
      $config = ['apitoken', 'bottoken', 'wutoken', 'wuloc'];
      $settings = ['litecoin', 'bitcoin', 'ethereum'];
      foreach($config as $variable)
      $statement = $db->prepare('INSERT INTO config (name, value) VALUES (:name, :value)');
      $statement->bindValue(':name', $variable, PDO::PARAM_STR);
      $statement->bindValue(':value', $_POST[$variable], PDO::PARAM_STR);
      $statement->execute();

      if ($_POST['log'])
      $db->exec("INSERT INTO config (name, value) VALUES ('log', '1')");
      else
      $db->exec("INSERT INTO config (name, value) VALUES ('log', '1')");

      if ((isset($_POST['wutoken'])) && isset($_POST['wuloc']))
      $db->exec("INSERT INTO settings (name, value) VALUES ('weather', '1')");
      else
      $db->exec("INSERT INTO settings (name, value) VALUES ('weather', '0')");

      $db->exec("INSERT INTO settings (name, value) VALUES ('lights', '0')");
      $db->exec("INSERT INTO responses (find, respond) VALUES ('test', 'It works!')");
      add_admin($_POST['user'], $_POST['pass']);
      foreach($settings as $variable)
      $statement = $db->prepare('INSERT INTO settings (name, value) VALUES (:name, :value)');
      $statement->bindValue(':name', $variable, PDO::PARAM_STR);
      $statement->bindValue(':value', '1', PDO::PARAM_STR);
      $statement->execute();

      file_put_contents('.htaccess', "<Files "db.sqlite">nDeny From Alln</Files>n<Files "sess*">nDeny From Alln</Files>");
      header("Refresh:1");

      disp_setup();
      else
      echo "Working directory is not writeable, either chown it to the webserver user and group or allow write permissions to everyone (insecure!)";
      ?>
      </body>
      </html>








      share|improve this question










      share|improve this question




      share|improve this question









      asked Feb 28 at 10:44









      Desultory

      335




      335

























          active

          oldest

          votes











          Your Answer




          StackExchange.ifUsing("editor", function ()
          return StackExchange.using("mathjaxEditing", function ()
          StackExchange.MarkdownEditor.creationCallbacks.add(function (editor, postfix)
          StackExchange.mathjaxEditing.prepareWmdForMathJax(editor, postfix, [["\$", "\$"]]);
          );
          );
          , "mathjax-editing");

          StackExchange.ifUsing("editor", function ()
          StackExchange.using("externalEditor", function ()
          StackExchange.using("snippets", function ()
          StackExchange.snippets.init();
          );
          );
          , "code-snippets");

          StackExchange.ready(function()
          var channelOptions =
          tags: "".split(" "),
          id: "196"
          ;
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function()
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled)
          StackExchange.using("snippets", function()
          createEditor();
          );

          else
          createEditor();

          );

          function createEditor()
          StackExchange.prepareEditor(
          heartbeatType: 'answer',
          convertImagesToLinks: false,
          noModals: false,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: null,
          bindNavPrevention: true,
          postfix: "",
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          );



          );








           

          draft saved


          draft discarded


















          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f188513%2fphp-based-groupme-bot-with-sqlite-and-control-panel%23new-answer', 'question_page');

          );

          Post as a guest



































          active

          oldest

          votes













          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes










           

          draft saved


          draft discarded


























           


          draft saved


          draft discarded














          StackExchange.ready(
          function ()
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fcodereview.stackexchange.com%2fquestions%2f188513%2fphp-based-groupme-bot-with-sqlite-and-control-panel%23new-answer', 'question_page');

          );

          Post as a guest













































































          Popular posts from this blog

          Greedy Best First Search implementation in Rust

          Function to Return a JSON Like Objects Using VBA Collections and Arrays

          C++11 CLH Lock Implementation