Message:
Send
IWA Chat Room - Choose a Nickname $msg
\n"; } ?>
Nickname:
query("LOCK TABLES `chatsessions` WRITE"); $result = $db->query("SELECT `id`, `nickname`, `ip`, `lastpoll` FROM `chatsessions` WHERE `status` != '0' AND `lastpoll` + $IDLETIMEOUT < UNIX_TIMESTAMP()"); if (!$result) { throw new Exception("Unable to SELECT from session table of '$DBNAME' database: (" . $db->errno . ") " . $db->error); } while (($row = $result->fetch_assoc()) != NULL) { // Hope these queries work, because we're ignoring errors... $db->query("UPDATE `chatsessions` SET `status` = '0', `updatetime` = UNIX_TIMESTAMP() WHERE `id` = '" . $row['id'] . "'"); $db->query("INSERT INTO `msgstore` (`csid`,`nickname`, `timestamp`, `body`) VALUES (" . "'" . $row['id'] . "', " . "'" . $db->real_escape_string($SERVERNAME) . "', " . "'" . ($row['lastpoll'] + $IDLETIMEOUT) . "', " . "'*** " . $db->real_escape_string($row['nickname']) . " [" . $db->real_escape_string($row['ip']) . "] " . "has departed the chat room. ***')"); } $result->free(); $db->query("UNLOCK TABLES"); } // Get the remote client IP address: $ip = $_SERVER['REMOTE_ADDR']; // If this web site operates behind a known remote proxy, find the actual client IP: for ($i = 0; $i < count($KNOWN_REVERSEPROXIES); $i++) { if (!strcmp($ip,$KNOWN_REVERSEPROXIES[$i]) && isset($_SERVER['HTTP_X_FORWARDED_FOR'])) { $ip = $_SERVER['HTTP_X_FORWARDED_FOR']; break; } } if (isset($_POST['nickname'])) { // Check to see if nickname is permitted and if it is unique $nickname = $_POST['nickname']; // Sanity check nickname - Limit the character set greatly // No double-quotes allowed! if (!preg_match('/^[a-zA-Z0-9._ -]{1,20}$/', $nickname) || !strcmp($SERVERNAME, $nickname)) { display_nickform("Invalid nickname. Please choose another."); } // Connect to the database: dbconnect(); // Update old sessions: update_sessions($db); // Is the nickname unique? $result = $db->query("SELECT `id` FROM `chatsessions` WHERE `nickname` = '" . $db->real_escape_string($nickname) . "' AND `status` != '0'"); if (!$result) { throw new Exception("Unable to perform SELECT query on session table in database '$DBNAME' to check for duplicate nicknames: (" . $db->errno . ") " . $db->error); } if ($result->num_rows != 0) { $db->close(); display_nickform("The nickname " . $nickname . " is already in use. Please choose another."); } $result->free(); // Create a new session in the database: if ($db->query("INSERT INTO `chatsessions` (`ip`, `starttime`, `updatetime`, `nickname`, `lastpoll`, `status`) VALUES ('" . $db->real_escape_string($ip) . "', UNIX_TIMESTAMP(), UNIX_TIMESTAMP(), '" . $db->real_escape_string($nickname) . "', UNIX_TIMESTAMP(), 1)") !== TRUE) { throw new Exception("Unable to perform INSERT query on '$DBNAME' database: (" . $db->errno . ") " . $db->error); } // Fetch the database session ID: $id = $db->insert_id; // Fetch the timestamp for the session start from the database: $result = $db->query("SELECT `starttime` FROM `chatsessions` WHERE `id` = '$id'"); if (!$result) { throw new Exception("Unable to perform SELECT query on '$DBNAME' database: (" . $db->errno . ") " . $db->error); } if ($result->num_rows != 1) { throw new Exception("SELECT query on '$DBNAME' database did not return a single row as expected, but returned " . $result->num_rows . " rows instead."); } $row = $result->fetch_assoc(); $ts = $row['starttime']; $result->free(); // Generate a new MD5 session identifier: $chatid = md5($CHATSECRET . $nickname . $id . $ip . $ts); // Now update the session in the database: if ($db->query("UPDATE `chatsessions` SET `chatid` = '$chatid' WHERE `id` = '$id'") !== TRUE) { throw new Exception("Unable to perform UPDATE query on '$DBNAME' database: (" . $db->errno . ") " . $db->error); } // Insert a new server message: if ($db->query("INSERT INTO `msgstore` (`csid`, `nickname`, `timestamp`, `body`) VALUES (" . "'" . $id . "', '" . $db->real_escape_string($SERVERNAME) . "', UNIX_TIMESTAMP(), '*** " . $db->real_escape_string($nickname) . " [" . $db->real_escape_string($ip) . "] has entered the chat room. ***')") !== TRUE) { throw new Exception("Unable to INSERT a new server message into the '$DBNAME' database: (" . $db->errno . ") " . $db->error); } $db->close(); display_main($chatid, $nickname); } if (strcmp($_SERVER['REQUEST_METHOD'], "POST")) { // Non-posts get the nickname login form: display_nickform(); } // If 'chatid' is set by a POST, then this is an Ajax query: if (isset($_POST['chatid'])) { $error = ''; $chatid = $_POST['chatid']; // VERY CAREFULLY sanity-check the timestamp. It's used unescaped in SQL // queries, so it MUST BE CLEAN to avoid SQL injection bugs. if (!isset($_POST['timestamp']) || !preg_match('/^\d{1,20}$/', $_POST['timestamp'])) { $timestamp = 0; } else { $timestamp = $_POST['timestamp']; } if (isset($_POST['getroster']) && !strcmp($_POST['getroster'], "1")) { $getroster = TRUE; } else { $getroster = FALSE; } if (isset($_POST['message'])) { $message = $_POST['message']; $message = preg_replace('/\n+$/s', '', $message); $message = preg_replace('/^\n+/s', '', $message); if (strlen($message) > $MAXMSGSIZE || count(preg_split('/\n/', $message)) > $MAXMSGLINES) { $error = "*** Your message was refused because it was too long or contained too many lines. ***"; $message = FALSE; } } else { $message = FALSE; } // Connect to the database: dbconnect(); // Update old sessions: update_sessions($db); // Extract the session information from the database: $result = $db->query("SELECT `id`, `status`, `ip`, `nickname`, UNIX_TIMESTAMP() as `timestamp` FROM `chatsessions` WHERE `chatid` = '" . $db->real_escape_string($chatid) . "'"); if (!$result) { throw new Exception("Unable to perform SELECT query on '$DBNAME' database: (" . $db->errno . ") " . $db->error); } if ($result->num_rows == 0) { // No such session! $db->close(); header("Content-type: text/plain"); print "ERROR"; exit(); } if ($result->num_rows != 1) { throw new Exception("SELECT query on '$DBNAME' database did not return a single row as expected, but returned " . $result->num_rows . " rows instead."); } $row = $result->fetch_assoc(); if (strcmp($ip, $row['ip'])) { // Client IP address doesn't match! Stolen session? $db->close(); header("Content-type: text/plain"); print "ERROR"; exit(); } $id = $row['id']; $status = $row['status']; $nickname = $row['nickname']; $ts = $row['timestamp']; $result->free(); // Valid session, so update "lastpoll" field: if ($db->query("UPDATE `chatsessions` SET `lastpoll` = '$ts' WHERE `id` = '$id'") !== TRUE) { throw new Exception("UPDATE query on '$DBNAME' failed while updating session idle timestamp: (" . $db->errno . ") " . $db->error); } // If status == 0 (it shouldn't), then update: if ($status == 0) { $status = 1; if ($db->query("UPDATE `chatsessions` SET `status` = '1', `updatetime` = '$ts' WHERE `id` = '$id'") !== TRUE) { throw new Exception("UPDATE query on '$DBNAME' failed while updating session status: (" . $db->errno . ") " . $db->error); } // Insert status change message: if ($db->query("INSERT INTO `msgstore` (`csid`, `nickname`, `timestamp`, `body`) VALUES (" . "'" . $id . "', '" . $db->real_escape_string($SERVERNAME) . "', UNIX_TIMESTAMP(), '*** " . $db->real_escape_string($nickname) . " [" . $db->real_escape_string($ip) . "] is now online in the chat room. ***')") !== TRUE) { throw new Exception("Unable to INSERT a new server message into the '$DBNAME' database: (" . $db->errno . ") " . $db->error); } } // If the user sent a message, insert it into the database: if ($message) { // Insert status change message: if ($db->query("INSERT INTO `msgstore` (`csid`, `nickname`, `timestamp`, `body`) VALUES (" . "'" . $id . "', '" . $db->real_escape_string($nickname) . "', UNIX_TIMESTAMP(), '" . $db->real_escape_string($message) . "')") !== TRUE) { throw new Exception("Unable to INSERT a new user message into the '$DBNAME' database: (" . $db->errno . ") " . $db->error); } } // Get roster updates: if ($getroster) { $result = $db->query("SELECT `nickname`, `status`, `updatetime` FROM `chatsessions` WHERE `status` != '0'"); } else { $result = $db->query("SELECT `nickname`, `status`, `updatetime` FROM `chatsessions` WHERE `updatetime` > '$timestamp'"); } if (!$result) { throw new Exception("Unable to SELECT from session table of '$DBNAME' database: (" . $db->errno . ") " . $db->error); } $roster = ''; while (($row = $result->fetch_assoc()) != NULL) { $roster .= $row['nickname'] . "\n" . $row['updatetime'] . "\n"; if ($row['status'] == 0) { $roster .= "Offline\n"; } else if ($row['status'] == 1) { $roster .= "Online\n"; } else { $roster .= "Away\n"; } } $result->free(); if (strlen($roster) > 0) { $roster = "ROSTER\n" . (count(preg_split('/\n/', $roster)) - 1) . "\n" . $roster; } // Get a list of new messages, or the last $MESSAGEHISTORY messages if this // is a new session: if ($timestamp) { $result = $db->query("SELECT `nickname`, `id`, `timestamp`, `body` FROM `msgstore` WHERE `timestamp` > '$timestamp' ORDER BY `timestamp` DESC"); } else { $result = $db->query("SELECT `nickname`, `id`, `timestamp`, `body` FROM `msgstore` WHERE `timestamp` + $HISTORYAGE > UNIX_TIMESTAMP() ORDER BY `timestamp` DESC LIMIT $MESSAGEHISTORY"); } if (!$result) { throw new Exception("Unable to SELECT from message storage table of '$DBNAME' database: (" . $db->errno . ") " . $db->error); } $messages = array(); while (($row = $result->fetch_assoc()) != NULL) { $body = $row['body']; $body = preg_replace('/^\n+/s' ,'', $body); $body = preg_replace('/\n+$/s' ,'', $body); $messages[] = $row['nickname'] . "\n" . $row['id'] . "\n" . $row['timestamp'] . "\n" . count(preg_split('/\n/', $body)) . "\n" . $body . "\n"; } $result->free(); $db->close(); $messages = array_reverse($messages); if (count($messages) > 0) { $messages = join('', $messages); $messages = "MESSAGE\n" . (count(preg_split('/\n/', $messages)) - 1) . "\n" . $messages; } else { $messages = ''; } $response = $roster . $messages; if (strlen($response) == 0) { $response = "NOOP\n0\n"; } // Return the Ajax response: header("Content-type: text/plain"); print $response; exit(); } throw new Exception("ERROR: Invalid POST resulted in invalid execution path!");