I wrote a page with Laravel to manage projects with Scrumpoker through blade syntax with controllers, models and Vue.js.
My problem is that I wrote the actual Scrumpoker in a single file.php file and it is loading by using a method through an onclick event of a form.
Now I want to split it up, make some refactoring and implement in my clean written .php Laravel files. I am doing this because it does not fetch every picture of my /storage folder correctly and to create a clean project.
Here is the code (only index.php + images folder with /themes/decksize/13plus1 or /themes/decksize/6plus1 with a.png/b.png/std.png sliced up in single pictures)
<?php error_reporting(0); ?>
<?php
session_start();
if (isset($_GET['name']) && ($_GET['name'] == "UserDebug" ||
substr($_GET['name'], 0, 4) == "tata")) {
exit;
}
if (isset($_GET['name']) && $_GET['name'] == '') {
// user is observer
unset($_GET['name']);
}
if (isset($_GET['name'])) {
$_GET['name'] = strip_tags($_GET['name']);
}
define('IDLE_TIMEOUT_SECONDS', 5);
define('IDLE_TIMEOUT_DELETE_SECONDS', 25);
define('PATH_TO_DATA_FILE', './storage/rooms');
define('LOCKFILE', './scrumlock');
define('DEBUG', false);
if (!isset($_GET['decksize'])) {
$decksize = '13plus1';
} else {
$decksize = $_GET['decksize'];
$_SESSION['decksize'] = $decksize;
}
if (!isset($_SESSION['decksize'])) {
$_SESSION['decksize'] = $decksize;
}
// valid cards - order is the same for the theme png-files
$validOptions = array(
'13plus1' => array(
"1" => "[ 0 ]",
"2" => "[ 1/2 ]",
"3" => "[ 1 ]",
"4" => "[ 2 ]",
"5" => "[ 3 ]",
"6" => "[ 5 ]",
"7" => "[ 8 ]",
"8" => "[ 13 ]",
"9" => "[ 20 ]",
"10" => "[ 40 ]",
"11" => "[ 100 ]",
"12" => "[ ? ]",
"13" => "[ C ]",
// 14 => backside of card
),
'6plus1' => array(
"1" => "[ 1 ] Piece of cake",
"2" => "[ 3 ] Hexenwerk",
"3" => "[ 8 ] Raketenwissenschaft",
"4" => "[ 100 ] O M G !",
"5" => "[ ? ] Ich brauche mehr details",
"6" => "[ C ] Kaffeepause",
// 7 => backside of card
),
);
// will be used to slice the theme.png image into x slices - one per card
define('CARDS_IN_THEME', sizeof($validOptions[$_SESSION['decksize']]) + 1);
function dbg($str)
{
if (DEBUG) {
echo $str;
}
}
// set standard theme if no theme is set
if (!isset($_GET['theme'])) {
$_GET['theme'] = 'A';
}
// players name matches tablename? == admin
$admin = false;
if (isset($_GET['name']) && isset($_GET['table']) && $_GET['name'] == $_GET['table']) {
$admin = true;
}
// calculate card width, height and check if theme is available on disk
$offsets = getCardOffset("1", $validOptions[$_SESSION['decksize']], $_GET['theme']);
if (is_array($offsets)) {
$cardWidth = $offsets[1];
$placeWidth = 20 + $offsets[1];
$cardHeight = $offsets[2];
$placeHeight = 20 + $offsets[2];
} else {
$cardWidth = 50;
$placeWidth = 100;
$cardHeight = 75;
$placeHeight = 95;
}
// Handle AJAX requests
// new players come here, their cards or ajax-commands to reset the table
if (isset($_GET['table']) && isset($_GET['ajax'])) {
// tabledata is stored in a file named same as table within /tmp
// for security - prevent writing to other directories than /tmp by stripping all dots and slashes
$table = str_replace(array('.', '/'), '', $_GET['table']);
// create a new game if the player is admin and no game exists
if (!file_exists(PATH_TO_DATA_FILE . $table) && $admin) {
touch(PATH_TO_DATA_FILE . $table);
}
// stop all players on playing on non existing tables
// ajax requests to non existing tables stop here
if (!file_exists(PATH_TO_DATA_FILE . $table)) {
echo 'Table does not exist.';
exit;
}
// making sure just ONE player fiddles arround with the array on the disk at the same time
while (!@mkdir(LOCKFILE)) {
sleep(2);
}
// read the tabledata from file
$filedata = unserialize(file_get_contents(PATH_TO_DATA_FILE . $table));
if (!is_array($filedata)) {
$filedata = array();
}
// kill the game if requested
if (isset($_GET['kill']) && $admin) {
$filedata = array();
unlink(PATH_TO_DATA_FILE . $table);
echo "table killed.";
rmdir(LOCKFILE);
exit;
}
// initiate new game when not done yet
if (!isset($filedata['table'])) {
$filedata['table'] = array();
}
if (!isset($filedata['history'])) {
$filedata['history'] = array();
}
if (!isset($filedata['message'])) {
$filedata['message'] = 'Welcome to Scrummy:';
}
// split game array in sub parts
$tabledata = $filedata['table']; // array of the current game (on the red blanket)
$tabledatahistory = $filedata['history']; // array holding previous game arrays (below the red blanket)
$players = $filedata['players']; // array holding last seen timestamps for players
$message = $filedata['message']; // message of the table
if (isset($_GET['options']) && $_GET['options']) {
// override message for the table
if (strpos($_GET['options'], 'https://it.ly/2NDNWF8') !== false) {
$_GET['options']
=
'<A href="' . $_GET['options'] . '" target="_blank">' . str_replace(
'https://it.ly/2NDNWF8',
'',
$_GET['options']
) . '</A>';
}
$filedata['message'] = $_GET['options'];
$message = $filedata['message'];
file_put_contents(PATH_TO_DATA_FILE . $table, serialize($filedata));
}
// check for user manipulation
$userIsSpoofingArround = false;
if (isset($_GET['name']) && isset($_GET['ID']) && $tabledata[$_GET['name']]['ID'] != $_GET['ID']) {
$userIsSpoofingArround = true;
}
if (isset($_GET['name']) && isset($tabledata[$_GET['name']]) && $userIsSpoofingArround) {
if ((time() - $players[$_GET['name']]) < IDLE_TIMEOUT_DELETE_SECONDS) {
dbg("[" . $tabledata[$_GET['name']]['ID'] . "] == [" . $_GET['ID'] . "]<br>");
echo 'AUTHENTICATION PROBLEM - FRAUD DETECTED!';
rmdir(LOCKFILE);
exit;
} else {
// user is spoofing another user who idled out. user can take the session
if ($_GET['ID']) {
$tabledata[$_GET['name']]['ID'] = $_GET['ID'];
dbg("updating ID<br>");
}
}
} else {
// echo "[".$tabledata[$_GET['name']]['ID']."] == [".$_GET['ID']."]<br>";
}
// put the current game into the history
if (isset($_GET['add']) && $admin) {
$tabledatahistory[] = $tabledata;
$tabledata = array();
$filedata['table'] = $tabledata;
$filedata['history'] = $tabledatahistory;
file_put_contents(PATH_TO_DATA_FILE . $table, serialize($filedata));
rmdir(LOCKFILE);
exit;
}
// set a card for a player if all _GET data is valid
if (
isset($_GET['guess']) && $_GET['guess'] != '' && isset($_GET['name']) && $_GET['name']
&& isset($tabledata[$_GET['name']])
&& $tabledata[$_GET['name']]['ID'] == $_GET['ID']
) {
if (in_array($_GET['guess'], array_keys($validOptions[$_SESSION['decksize']]))) {
dbg("saving guess and updating time<br>");
$tabledata[$_GET['name']] = array('name' => $_GET['name'], 'guess' => $_GET['guess'], 'ID' => $_GET['ID']);
$players[$_GET['name']] = time();
}
}
// recognition of new player without a card - prepare slot
if (isset($_GET['name']) && !isset($tabledata[$_GET['name']]) && isset($_GET['name']) && $_GET['name']) {
$tabledata[$_GET['name']] = array('name' => $_GET['name'], 'guess' => '...', 'ID' => $_GET['ID']);
dbg("adding new player with guess ...<br>");
}
// drop ideling players after IDLE_TIMEOUT_SECONDS
if (isset($_GET['name']) && isset($tabledata[$_GET['name']]) && $_GET['name'] && !$userIsSpoofingArround) {
$players[$_GET['name']] = time();
dbg("updating time<br>");
}
// combine history and current game into one array
$filedata['table'] = $tabledata;
$filedata['history'] = $tabledatahistory;
$filedata['players'] = $players;
$filedata['message'] = $message;
// write table data to disk
if (isset($_GET['name']) && $_GET['name']) {
file_put_contents(PATH_TO_DATA_FILE . $table, serialize($filedata));
dbg("writing data to disk<br>");
}
// prepare layout of the webpage
// show all cards
$showAllCards = true;
// echo table header with names
ksort($players);
$playernames = array();
if (is_array($players)) {
$playernames = array_keys($players);
}
$totalPlayers = 0;
$activePlayers = 0;
$playersOnTable = 0;
// check if some players did not choose yet
if (is_array($playernames)) {
foreach ($playernames as $eachPlayername) {
$totalPlayers++;
if ((time() - $players[$eachPlayername]) < IDLE_TIMEOUT_SECONDS) {
$activePlayers++;
}
if ((time() - $players[$eachPlayername]) < IDLE_TIMEOUT_DELETE_SECONDS) {
$playersOnTable++;
}
if (
$tabledata[$eachPlayername]['guess'] == '...'
&& (time() - $players[$eachPlayername]) < IDLE_TIMEOUT_SECONDS
) {
$showAllCards = false;
}
}
}
// automatic new row
if ($showAllCards && $activePlayers > 1) {
$tabledatahistory[] = $tabledata;
//$tabledata = array(); <-- will not work - enables session hijacking
foreach ($tabledata as $username => $userarray) {
$tabledata[$username]['guess'] = '...';
}
$filedata['table'] = $tabledata;
$filedata['history'] = $tabledatahistory;
file_put_contents(PATH_TO_DATA_FILE . $table, serialize($filedata));
}
rmdir(LOCKFILE);
echo '<A href="javascript:clearTimeout(TIMEOUT)">Take A Break(STOP REFRESH)</A><br><br>';
echo '<h2>' . $message . '</h2>';
echo '<style>
.striped-border {
border: 1px dashed #000;
width: 50%;
margin: auto;
margin-top: 5%;
margin-bottom: 5%;
}
hr {
height: 1px;
color: #123455;
background-color: #123455;
border: none;
}
.center {
margin: auto;
width: 60%;
border: 15px solid #000000;
padding: 10px;
text-align: center
}
</style>
<div class=center>Players On Table: ' . $playersOnTable . "<br>";
echo 'Total Player:' . $totalPlayers . "<br>";
echo 'Active Players: ' . $activePlayers . "<br>";
echo '<div class="header">';
if (is_array($playernames)) {
foreach ($playernames as $eachPlayerName) {
$id = '(' . $tabledata[$eachPlayerName]['ID'] . '/' . $_GET['ID'] . ')';
$id = '';
if (time() - $players[$eachPlayerName] < IDLE_TIMEOUT_SECONDS) {
echo '<div class="place" style="text-align:left"' . $placeWidth . 'px;overflow:hidden">' . '<strong>' . 'Player:' . '</strong>' . ' ' . $eachPlayerName . '<br>' ./*'<b>'.hash('sha512',session_id($eachPlayerName)).'</b>'.*/ $id
. '</div>';
} elseif (time() - $players[$eachPlayerName] < IDLE_TIMEOUT_DELETE_SECONDS) {
echo '<div class="place" style="width:' . $placeWidth . 'px;overflow:hidden">' . $eachPlayerName . $id
. '<br><i>INACTIVE</i></div>';
}
}
echo '</div>';
// CURRENT TABLE
echo '<div class="currentTable" style="width:' . ($playersOnTable * $placeWidth) . '"><nobr>';
foreach ($playernames as $eachPlayerName) {
$styleaddon = '';
$ownPlace = (isset($_GET['name']) && $tabledata[$eachPlayerName]['name'] == $_GET['name']);
$playerPlayedACard = ($tabledata[$eachPlayerName]['guess'] != '...');
if (time() - $players[$eachPlayerName] < IDLE_TIMEOUT_DELETE_SECONDS) {
echo '<div class="place"><center>';
$offsets = getCardOffset($tabledata[$eachPlayerName]['guess'], $validOptions[$_SESSION['decksize']], $_GET['theme']);
if (is_array($offsets)) {
// show nifty cards
echo '' . (($showAllCards || ($ownPlace && $playerPlayedACard))
?
// show card face up
'<div style="width:' . $cardWidth . ';height:' . $cardHeight . ';background-image:url(\'/storage/'
. $offsets[3] . '\');background-position:' . $offsets[0] . ' 0px;"> </div>'
: ($playerPlayedACard
?
// show card face down
'<div style="width:' . $cardWidth . ';height:' . $cardHeight
. ';background-image:url(\'' . $offsets[3] . '\');background-position:'
. (-(CARDS_IN_THEME - 1) * $cardWidth) . 'px 0px;"> </div>'
:
// show empty place
'<div style="' . $styleaddon . 'width:' . $cardWidth . ';height:' . $cardHeight
. ';overflow:hidden;"> </div>')) . '';
} else {
// theme not found or erroneous - show text cards
echo '' . (($showAllCards || ($ownPlace && $playerPlayedACard))
?
// show card face up
'<div class="card"><span style="height:' . $cardHeight
. 'px; width:1px; vertical-align:middle"></span>'
. $validOptions[$_SESSION['decksize']][$tabledata[$eachPlayerName]['guess']] . '</div>'
: ($playerPlayedACard
?
// show card face down
'<img src="/storage/images/back.jpg?t=' . filemtime('images/back.jpg') . '>'
:
// show empty place
'<div style="' . $styleaddon . 'width:' . $cardWidth . ';height:' . $cardHeight
. ';overflow:hidden;"> </div>')) . '';
// '<img src="./images/blank2.jpg">'));
}
echo '</center></div>';
}
}
echo '</nobr></div>';
$tabledatahistory = array_reverse($tabledatahistory);
// HISTORY
foreach ($tabledatahistory as $eachHistory) {
echo '<div class="historyTable" style="width:' . ($playersOnTable * $placeWidth) . '">';
foreach ($playernames as $eachPlayerName) {
if (time() - $players[$eachPlayerName] < IDLE_TIMEOUT_DELETE_SECONDS) {
echo '<div class="place"><p><i>' . $eachPlayerName . '<hr>' . '</i><center>';
$offsets = getCardOffset($eachHistory[$eachPlayerName]['guess'], $validOptions[$_SESSION['decksize']], $_GET['theme']);
if (is_array($offsets)) {
// show nifty cards
echo '<div style="width:' . $cardWidth . ';height:' . $offsets[2] . ';background-image:url(\'themes/13plus1/std.png?1435657352'\');background-position:' . $offsets[0] . ' 0px;"> </div>';
} else {
// theme not found or erroneous - show text cards
echo '<div class="card"><span style="height:' . $cardHeight
. 'px; width:1px; vertical-align:middle"></span>'
. $validOptions[$_SESSION['decksize']][$eachHistory[$eachPlayerName]['guess']] . '</div>';
}
echo '</center></div>';
}
}
echo '</div>';
}
}
// echo '<pre>';
exit;
}
$ID = session_id();
/**
* @param $guess
* @param $validOptions
* @param $theme
* @return string
*/
function getCardOffset($guess, $validOptions, $theme)
{
$return = 0;
$found = false;
$imageName = 'storage/themes/' . $_SESSION['decksize'] . '/' . str_replace(array('/', '.'), '', $theme) . '.png';
if (file_exists($imageName)) {
$img = imagecreatefrompng($imageName);
if ($img) {
$width = imagesx($img);
$cardWidth = $width / CARDS_IN_THEME;
foreach ($validOptions as $key => $val) {
if ($guess != $key) {
$return -= $cardWidth;
} else {
$found = true;
break;
}
}
} else {
return false;
}
} else {
return false;
}
if (!$found) {
return false;
}
return array($return . "px", $cardWidth, imagesy($img), $imageName . '?' . filemtime($imageName));
}
if (!isset($_GET['table'])) {
$folder = 'themes/' . $_SESSION['decksize'] . '/';
$otherfolder = 'themes/6plus1' . $_SESSION['secdecksize'] . '/';
exit;
} else {
// handle HTML page for the client
?>
<html>
<head>
<title>Scrummy</title>
<link href="//cdn.muicss.com/mui-0.9.43/css/mui.min.css" rel="stylesheet" type="text/css" />
<script src="//cdn.muicss.com/mui-0.9.43/js/mui.min.js"></script>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/bulma/0.7.5/css/bulma.min.css">
<script defer src="https://use.fontawesome.com/releases/v5.3.1/js/all.js"></script>
<style>
body {
background-color: coral ;
}
.card {
width: <?php echo $cardWidth; ?>px;
height: <?php echo $cardHeight; ?>px;
overflow: hidden;
background-image: url('/storage/images/blank.jpg');
background-size: <?php echo $cardWidth; ?>px auto;
border: 0px solid red;
}
* {
font-family: Verdana;
font-size: 8pt;
}
.currentTable {
border: 0px solid black;
background-image: url('storage/images/rw.png');
height: <?php echo $placeHeight; ?>px;
}
.historyTable {
border: 0px solid dotted;
height: <?php echo $placeHeight; ?>px;
}
.place {
border: 0px solid black;
overflow: hidden;
float: left;
text-align: center;
width: <?php echo $placeWidth; ?>px;
}
.currentTable .place {
margin-top: 10px;
}
.historyTable .place {
margin-top: 10px;
}
.header {
border: 0px solid black;
height: 25px;
clear: both;
}
</style>
<script>
var TIMEOUT;
var VALUE = "...";
function statusCommand(cmd, user, table, options) {
if (options == undefined) {
options = '';
}
if (window.XMLHttpRequest) {
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
} else {
// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
}
}
xmlhttp.open("GET", "?ID=<?php echo session_id(); ?>&ajax&name=" + user + "&table=" + table + "&" + cmd + "&options=" + options, true);
xmlhttp.send();
}
function showUser(str, name, table) {
if (str == "") {
document.getElementById("txtHint").innerHTML = "";
return;
}
if (str != "..." && str != "AUTO") {
VALUE = str;
document.getElementById("guess").value = "...";
}
if (window.XMLHttpRequest) {
// code for IE7+, Firefox, Chrome, Opera, Safari
xmlhttp = new XMLHttpRequest();
} else {
// code for IE6, IE5
xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.onreadystatechange = function() {
if (xmlhttp.readyState == 4 && xmlhttp.status == 200) {
document.getElementById("txtHint").innerHTML = xmlhttp.responseText;
}
}
if (str == "AUTO") {
xmlhttp.open("GET", "?theme=<?php echo $_GET['theme']; ?>&ID=<?php echo session_id(); ?>&ajax&table=" + table + "&name=" + name, true);
} else {
xmlhttp.open("GET", "?theme=<?php echo $_GET['theme']; ?>&ID=<?php echo session_id(); ?>&ajax&table=" + table + "&guess=" + str + "&name=" + name, true);
}
xmlhttp.send();
if (document.getElementById("txtHint").innerHTML != "Table does not exist.") {} else {
VALUE = "...";
}
timeout_init();
}
function timeout_init() {
clearTimeout(TIMEOUT);
TIMEOUT = setTimeout('showUser("AUTO","<?php echo $_GET['name']; ?>","<?php echo $_GET['table']; ?>")', 2000);
}
function initCards() {
showUser("AUTO", "<?php echo $_GET['name']; ?>", "<?php echo $_GET['table']; ?>");
timeout_init();
}
</script>
</head>
<body onLoad="initCards()">
<?php
for ($i = 8; $i > 0; $i--) {
//echo '<img src="cards/E'.$i.'.png" width="50">';
}
//echo '<br>';
?>
<form method="GET" onsubmit="javascript:return false;" class="mui-form">
<?php
if (isset($_GET['name'])) {
?>
<div class="mui-select">
<select id="guess" name="guess" onchange="showUser(this.value,'<?php echo $_GET['name']; ?>','<?php echo $_GET['table']; ?>')">
<option value="...">Select Your Card:</option>
<?php
foreach ($validOptions[$_SESSION['decksize']] as $key => $val) {
echo "<option value=\"" . $key . "\">" . $val . "</option>\n";
}
?>
</select></div>
<?php
foreach ($validOptions[$_SESSION['decksize']] as $key => $val) {
$offsets = getCardOffset($key, $validOptions[$_SESSION['decksize']], $_GET['theme']);
echo '<div class="place"><center><A href="javascript:showUser(\'' . $key . '\',\'' . $_GET['name']
. '\',\'' . $_GET['table'] . '\')">';
if (is_array($offsets)) {
// show nifty cards
echo '' .
'<div style="width:' . $cardWidth . ';height:' . $cardHeight . ';background-image:url(\''.
$offsets[3] . '\');background-position:' . $offsets[0] . ' 0px;"> </div>';
} else {
// theme not found or erroneous - show text cards
echo '' .
// show card face up
'<div class="card"><span style="height:' . $cardHeight
. 'px; width:1px; vertical-align:middle"></span>'
. $validOptions[$_SESSION['decksize']][$tabledata[$eachPlayerName]['guess']] . '</div>';
}
echo '</A></center></div>';
}
echo '<br style="clear:both">';
// echo '<A href="javascript:clearTimeout(TIMEOUT)">STOP REFRESH</A>';
?>
<?php
} else {
?>
<input name="message" size="100" onkeypress="statusCommand('message', '<?php echo $_GET['name']; ?>', '<?php echo $_GET['table']; ?>', this.value)" onkeyup="statusCommand('message', '<?php echo $_GET['name']; ?>', '<?php echo $_GET['table']; ?>', this.value)" onchange="statusCommand('message', '<?php echo $_GET['name']; ?>', '<?php echo $_GET['table']; ?>', this.value)" onblur="statusCommand('message', '<?php echo $_GET['name']; ?>', '<?php echo $_GET['table']; ?>', this.value)">
<?php
}
?>
</form>
<br>
<?php
if ($admin) {
echo '<mark>' . 'You`re the Scrumleader' . '</mark>' . '<br>';
?>
<A href="javaScript:statusCommand('kill','<?php echo $_GET['name']; ?>','<?php echo $_GET['table']; ?>')">Reset</A> the current game
<br>
<A href="javaScript:statusCommand('add','<?php echo $_GET['name']; ?>','<?php echo $_GET['table']; ?>')">New</A> Round? (Adds new game row)
<br>
<?php
}
?>
<div id="txtHint"><b>Cards are shown here</b></div>
</body>
</html>
<?php
}
?>