mirror of
https://github.com/smogon/pokemon-showdown-client.git
synced 2026-03-21 09:35:44 -05:00
Remove old action.php and replays
Our new API replacement for action.php is in https://github.com/smogon/pokemon-showdown-loginserver I haven't completely deleted the old-replays folder because there are some things we haven't replaced that I don't know what to do with... I guess that'll come in a future commit.
This commit is contained in:
parent
dbd4a9ec66
commit
21de8d92c6
39
action.php
39
action.php
|
|
@ -1,39 +0,0 @@
|
|||
<?php
|
||||
|
||||
/*
|
||||
|
||||
License: GPLv2 or later
|
||||
<http://www.gnu.org/licenses/gpl-2.0.html>
|
||||
|
||||
*/
|
||||
|
||||
error_reporting(E_ALL);
|
||||
|
||||
include_once __DIR__ . '/config/config.inc.php';
|
||||
|
||||
if (@$_GET['act'] === 'dlteam') {
|
||||
header("Content-Type: text/plain; charset=utf-8");
|
||||
if (substr(@$_SERVER['HTTP_REFERER'], 0, 32) !== 'https://' . $psconfig['routes']['client']) {
|
||||
// since this is only to support Chrome on HTTPS, we can get away with a very specific referer check
|
||||
die("access denied");
|
||||
}
|
||||
echo base64_decode(@$_GET['team']);
|
||||
die();
|
||||
}
|
||||
|
||||
if (preg_match('/^http\\:\\/\\/[a-z0-9]+\\.psim\\.us\\//', $_SERVER['HTTP_REFERER'] ?? '')) {
|
||||
header("Access-Control-Allow-Origin: *");
|
||||
} else if ($_POST['sid'] ?? null) {
|
||||
header("Access-Control-Allow-Origin: *");
|
||||
}
|
||||
// header("X-Debug: " . @$_SERVER['HTTP_REFERER']);
|
||||
|
||||
require_once __DIR__ . '/lib/ntbb-session.lib.php';
|
||||
include_once __DIR__ . '/config/servers.inc.php';
|
||||
include_once __DIR__ . '/lib/dispatcher.lib.php';
|
||||
|
||||
$dispatcher = new ActionDispatcher(array(
|
||||
new DefaultActionHandler(),
|
||||
new LadderActionHandler()
|
||||
));
|
||||
$dispatcher->executeActions();
|
||||
|
|
@ -1,555 +0,0 @@
|
|||
<?php
|
||||
|
||||
class ActionDispatcher {
|
||||
private $reqs;
|
||||
private $multiReqs = false;
|
||||
private $reqData;
|
||||
/**
|
||||
* API request output should not be valid JavaScript.
|
||||
*
|
||||
* This is to protect against a CSRF-like attack. Imagine you have an API:
|
||||
*
|
||||
* https://example.com/getmysecrets.json
|
||||
*
|
||||
* Which returns:
|
||||
*
|
||||
* {"yoursecrets": [1, 2, 3]}
|
||||
*
|
||||
* An attacker could trick a user into visiting a site overriding the
|
||||
* Array or Object constructor, and then containing:
|
||||
*
|
||||
* <script src="https://example.com/getmysecrets.json"></script>
|
||||
*
|
||||
* This could let them steal the secrets. In modern times, browsers
|
||||
* are protected against this kind of attack, but our `]` adds some
|
||||
* safety for older browsers.
|
||||
*
|
||||
* Adding `]` to the beginning makes sure that the output is a syntax
|
||||
* error in JS, so treating it as a JS file will simply crash and fail.
|
||||
*/
|
||||
private $outPrefix = ']';
|
||||
private $outArray = array();
|
||||
|
||||
public function __construct($handlers) {
|
||||
$this->handlers = $handlers;
|
||||
if (empty($_REQUEST)) {
|
||||
$this->reqs = null;
|
||||
if (substr($_SERVER["CONTENT_TYPE"] ?? '', 0, 16) === 'application/json') {
|
||||
// screw you too Axios
|
||||
// also come on PHP, you could just support JSON natively instead of putting me through this
|
||||
$input = trim(file_get_contents('php://input'));
|
||||
if ($input[0] === '[') {
|
||||
$this->reqs = json_decode($input, true);
|
||||
} else if ($input[0] === '{') {
|
||||
$this->reqs = [json_decode($input, true)];
|
||||
}
|
||||
}
|
||||
|
||||
if (empty($this->reqs)) die("no request data found - you need to send some sort of data");
|
||||
$_POST['is_post_request'] = true;
|
||||
} else {
|
||||
$this->reqs = [$_REQUEST];
|
||||
}
|
||||
if (@$_REQUEST['json']) {
|
||||
$this->reqs = json_decode($_REQUEST['json'], true);
|
||||
$this->multiReqs = true;
|
||||
}
|
||||
}
|
||||
|
||||
public function setPrefix($prefix) {
|
||||
$this->outPrefix = $prefix;
|
||||
}
|
||||
|
||||
public function getServerHostName($serverid) {
|
||||
global $PokemonServers;
|
||||
$server = @$PokemonServers[$serverid];
|
||||
return $server ? $server['server'] : $serverid;
|
||||
}
|
||||
|
||||
public function verifyCrossDomainRequest() {
|
||||
global $psconfig;
|
||||
// No cross-domain multi-requests for security reasons.
|
||||
// No need to do anything if this isn't a cross-domain request.
|
||||
if ($this->multiReqs || !isset($_SERVER['HTTP_ORIGIN'])) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$origin = $_SERVER['HTTP_ORIGIN'];
|
||||
$prefix = null;
|
||||
foreach ($psconfig['cors'] as $i => &$j) {
|
||||
if (!preg_match($i, $origin)) continue;
|
||||
$prefix = $j;
|
||||
break;
|
||||
}
|
||||
if ($prefix === null) {
|
||||
// Bogus request.
|
||||
return '';
|
||||
}
|
||||
|
||||
// Valid CORS request.
|
||||
header('Access-Control-Allow-Origin: ' . $origin);
|
||||
header('Access-Control-Allow-Credentials: true');
|
||||
return $prefix;
|
||||
}
|
||||
|
||||
public function getIp() {
|
||||
global $users;
|
||||
return $users->getIp();
|
||||
}
|
||||
|
||||
public function findServer() {
|
||||
global $PokemonServers;
|
||||
|
||||
$serverid = @$this->reqData['serverid'];
|
||||
$server = null;
|
||||
$ip = $this->getIp();
|
||||
if (!isset($PokemonServers[$serverid])) {
|
||||
// Try to find the server by source IP, rather than by serverid.
|
||||
if ($serverid === 'testtimeout') {
|
||||
foreach ($PokemonServers as &$i) {
|
||||
gethostbyname($i['server']);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
} else {
|
||||
$server = & $PokemonServers[$serverid];
|
||||
if (empty($server['skipipcheck']) && empty($server['token']) && $serverid !== 'showdown') {
|
||||
if (!isset($server['ipcache'])) {
|
||||
$server['ipcache'] = gethostbyname($server['server']);
|
||||
}
|
||||
if ($ip !== $server['ipcache']) return null;
|
||||
}
|
||||
}
|
||||
if (!empty($server['token'])) {
|
||||
if ($server['token'] !== md5($this->reqData['servertoken'] ?? '')) return null;
|
||||
}
|
||||
return $server;
|
||||
}
|
||||
|
||||
public function executeActions() {
|
||||
$outArray = null;
|
||||
if ($this->multiReqs) $outArray = array();
|
||||
|
||||
foreach ($this->reqs as $this->reqData) {
|
||||
$this->reqData = array_merge($_REQUEST, $this->reqData);
|
||||
if (!isset($this->reqData['act'])) die("action not found - make sure your request data includes act=something");
|
||||
$action = $this->reqData['act'];
|
||||
if (!ctype_alnum($action)) die("invalid action: " . var_export($action, true));
|
||||
$out = array();
|
||||
|
||||
foreach ($this->handlers as &$i) {
|
||||
if (is_callable(array($i, $action))) {
|
||||
$i->$action($this, $this->reqData, $out);
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->multiReqs) $outArray[] = $out;
|
||||
}
|
||||
// json output
|
||||
if ($this->outPrefix !== '') {
|
||||
// Technically this is not JSON because of the initial prefix.
|
||||
header('Content-Type: text/plain; charset=utf-8');
|
||||
} else {
|
||||
header('Content-Type: application/json');
|
||||
}
|
||||
if ($this->multiReqs) {
|
||||
die($this->outPrefix . json_encode($outArray));
|
||||
} else {
|
||||
die($this->outPrefix . json_encode($out));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class DefaultActionHandler {
|
||||
public function login($dispatcher, &$reqData, &$out) {
|
||||
global $users, $curuser;
|
||||
$challengeprefix = $dispatcher->verifyCrossDomainRequest();
|
||||
|
||||
if (!$_POST) die('for security reasons, logins must happen with POST data');
|
||||
if (empty($reqData['name']) || empty($reqData['pass'])) die('incorrect login data, you need "name" and "pass" fields');
|
||||
try {
|
||||
$users->login($reqData['name'], $reqData['pass']);
|
||||
} catch (Exception $e) {
|
||||
$out['error'] = $e->getMessage() . "\n" . $e->getFile() . '(' . $e->getLine() . ')' . "\n" . $e->getTraceAsString();
|
||||
}
|
||||
unset($curuser['userdata']);
|
||||
$out['curuser'] = $curuser;
|
||||
$out['actionsuccess'] = ($curuser ? $curuser['loggedin'] : false);
|
||||
$serverhostname = '' . $dispatcher->getServerHostName(@$reqData['serverid']);
|
||||
$challengekeyid = !isset($reqData['challengekeyid']) ? -1 : intval($reqData['challengekeyid']);
|
||||
$challenge = !isset($reqData['challenge']) ? '' : $reqData['challenge'];
|
||||
if (!$challenge) {
|
||||
$challenge = !isset($reqData['challstr']) ? '' : $reqData['challstr'];
|
||||
}
|
||||
$out['assertion'] = $users->getAssertion($curuser['userid'], $serverhostname, null,
|
||||
$challengekeyid, $challenge, $challengeprefix);
|
||||
}
|
||||
|
||||
public function register($dispatcher, &$reqData, &$out) {
|
||||
global $users, $curuser;
|
||||
$challengeprefix = $dispatcher->verifyCrossDomainRequest();
|
||||
|
||||
$serverhostname = '' . $dispatcher->getServerHostName(@$reqData['serverid']);
|
||||
$user = [
|
||||
'username' => @$_POST['username'],
|
||||
];
|
||||
$userid = $users->userid($user['username']);
|
||||
if ((mb_strlen($userid) < 1) || ctype_digit($userid)) {
|
||||
$out['actionerror'] = 'Your username must contain at least one letter.';
|
||||
} else if (substr($userid, 0, 5) === 'guest') {
|
||||
$out['actionerror'] = 'Your username cannot start with \'guest\'.';
|
||||
} else if (mb_strlen($user['username']) > 18) {
|
||||
$out['actionerror'] = 'Your username must be less than 19 characters long.';
|
||||
} else if (mb_strlen(@$_POST['password']) < 5) {
|
||||
$out['actionerror'] = 'Your password must be at least 5 characters long.';
|
||||
} else if (@$_POST['password'] !== @$_POST['cpassword']) {
|
||||
$out['actionerror'] = 'Your passwords do not match.';
|
||||
} else if (trim(strtolower(@$_POST['captcha'])) !== 'pikachu') {
|
||||
$out['actionerror'] = 'Please answer the anti-spam question given.';
|
||||
} else if (($registrationcount = $users->getRecentRegistrationCount()) === false) {
|
||||
$out['actionerror'] = 'A database error occurred. Please try again.';
|
||||
} else if ($registrationcount >= 2) {
|
||||
$out['actionerror'] = 'You can\'t register more than two usernames every two hours. Try again later.';
|
||||
} else if ($user = $users->addUser($user, $_POST['password'])) {
|
||||
$challengekeyid = !isset($reqData['challengekeyid']) ? -1 : intval($reqData['challengekeyid']);
|
||||
$challenge = !isset($reqData['challenge']) ? '' : $reqData['challenge'];
|
||||
if (!$challenge) {
|
||||
$challenge = !isset($reqData['challstr']) ? '' : $reqData['challstr'];
|
||||
}
|
||||
$out['curuser'] = $user;
|
||||
$out['assertion'] = $users->getAssertion($user['userid'],
|
||||
$serverhostname, $user, $challengekeyid, $challenge, $challengeprefix);
|
||||
$out['actionsuccess'] = true;
|
||||
} else {
|
||||
$out['actionerror'] = 'Your username is already taken.';
|
||||
}
|
||||
}
|
||||
|
||||
public function changepassword($dispatcher, &$reqData, &$out) {
|
||||
global $users, $curuser;
|
||||
|
||||
if (!$_POST ||
|
||||
!isset($reqData['oldpassword']) ||
|
||||
!isset($reqData['password']) ||
|
||||
!isset($reqData['cpassword'])) {
|
||||
$out['actionerror'] = 'Invalid request.';
|
||||
} else if (!$curuser['loggedin']) {
|
||||
$out['actionerror'] = 'Your session has expired. Please log in again.';
|
||||
} else if ($reqData['password'] !== $reqData['cpassword']) {
|
||||
$out['actionerror'] = 'Your new passwords do not match.';
|
||||
} else if (!$users->passwordVerify($curuser['userid'], $reqData['oldpassword'])) {
|
||||
$out['actionerror'] = 'Your old password was incorrect.';
|
||||
} else if (mb_strlen($reqData['password']) < 5) {
|
||||
$out['actionerror'] = 'Your new password must be at least 5 characters long.';
|
||||
} else if (!$users->modifyUser($curuser['userid'], array(
|
||||
'password' => $reqData['password']))) {
|
||||
$out['actionerror'] = 'A database error occurred. Please try again.';
|
||||
} else {
|
||||
$out['actionsuccess'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
public function changeusername($dispatcher, &$reqData, &$out) {
|
||||
global $users, $curuser;
|
||||
|
||||
if (!$_POST ||
|
||||
!isset($reqData['username'])) {
|
||||
$out['actionerror'] = 'Invalid request.';
|
||||
} else if (!$curuser['loggedin']) {
|
||||
$out['actionerror'] = 'Your session has expired. Please log in again.';
|
||||
} else if (!$users->modifyUser($curuser['userid'], array(
|
||||
'username' => $reqData['username']))) {
|
||||
$out['actionerror'] = 'A database error occurred. Please try again.';
|
||||
} else {
|
||||
$out['actionsuccess'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
public function logout($dispatcher, &$reqData, &$out) {
|
||||
global $users, $curuser, $psconfig;
|
||||
|
||||
if (!$_POST ||
|
||||
!isset($reqData['userid']) ||
|
||||
// some CSRF protection (client must know current userid)
|
||||
($reqData['userid'] !== $curuser['userid'])) {
|
||||
die;
|
||||
}
|
||||
$users->logout(); // this kills the `sid` cookie
|
||||
setcookie('showdown_username', '', time()-60*60*24*2, '/', $psconfig['routes']['client']);
|
||||
$out['actionsuccess'] = true;
|
||||
}
|
||||
|
||||
public function getassertion($dispatcher, &$reqData, &$out) {
|
||||
global $users, $curuser;
|
||||
$challengeprefix = $dispatcher->verifyCrossDomainRequest();
|
||||
|
||||
$serverhostname = '' . $dispatcher->getServerHostName(@$reqData['serverid']);
|
||||
$challengekeyid = !isset($reqData['challengekeyid']) ? -1 : intval($reqData['challengekeyid']);
|
||||
$challenge = !isset($reqData['challenge']) ? '' : $reqData['challenge'];
|
||||
if (!$challenge) {
|
||||
$challenge = !isset($reqData['challstr']) ? '' : $reqData['challstr'];
|
||||
}
|
||||
header('Content-Type: text/plain; charset=utf-8');
|
||||
if (empty($reqData['userid'])) {
|
||||
$userid = $curuser['userid'];
|
||||
if ($userid === 'guest') {
|
||||
// Special error message for this case.
|
||||
die(';');
|
||||
}
|
||||
} else {
|
||||
$userid = $users->userid($reqData['userid']);
|
||||
}
|
||||
$serverhostname = htmlspecialchars($serverhostname); // Protect against theoretical IE6 XSS
|
||||
die($users->getAssertion($userid, $serverhostname, null, $challengekeyid, $challenge, $challengeprefix));
|
||||
}
|
||||
|
||||
public function upkeep($dispatcher, &$reqData, &$out) {
|
||||
global $users, $curuser;
|
||||
$challengeprefix = $dispatcher->verifyCrossDomainRequest();
|
||||
|
||||
$out['loggedin'] = $curuser['loggedin'];
|
||||
$userid = '';
|
||||
if ($curuser['loggedin']) {
|
||||
$out['username'] = $curuser['username'];
|
||||
$userid = $curuser['userid'];
|
||||
} else if (isset($_COOKIE['showdown_username'])) {
|
||||
$out['username'] = $_COOKIE['showdown_username'];
|
||||
$userid = $users->userid($out['username']);
|
||||
}
|
||||
if ($userid !== '') {
|
||||
$serverhostname = '' . $dispatcher->getServerHostName(@$reqData['serverid']);
|
||||
$challengekeyid = !isset($reqData['challengekeyid']) ? -1 : intval($reqData['challengekeyid']);
|
||||
$challenge = !isset($reqData['challenge']) ? '' : $reqData['challenge'];
|
||||
if (!$challenge) {
|
||||
$challenge = !isset($reqData['challstr']) ? '' : $reqData['challstr'];
|
||||
}
|
||||
$out['assertion'] = $users->getAssertion($userid, $serverhostname, null, $challengekeyid, $challenge, $challengeprefix);
|
||||
}
|
||||
}
|
||||
|
||||
public function updateuserstats($dispatcher, &$reqData, &$out) {
|
||||
global $psdb;
|
||||
|
||||
$server = $dispatcher->findServer();
|
||||
if (!$server) {
|
||||
$out = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
$date = @$reqData['date'];
|
||||
$usercount = @$reqData['users'];
|
||||
if (!is_numeric($date) || !is_numeric($usercount)) {
|
||||
$out = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
$out = !!$psdb->query(
|
||||
"INSERT INTO `ntbb_userstats` (`serverid`, `date`, `usercount`) " .
|
||||
"VALUES ('" . $psdb->escape($server['id']) . "', '" . $psdb->escape($date) . "', '" . $psdb->escape($usercount) . "') " .
|
||||
"ON DUPLICATE KEY UPDATE `date`='" . $psdb->escape($date) . "', `usercount`='" . $psdb->escape($usercount) . "'");
|
||||
|
||||
if ($server['id'] === 'showdown') {
|
||||
$psdb->query(
|
||||
"INSERT INTO `ntbb_userstatshistory` (`date`, `usercount`) " .
|
||||
"VALUES ('" . $psdb->escape($date) . "', '" . $psdb->escape($usercount) . "')");
|
||||
}
|
||||
$dispatcher->setPrefix(''); // No need for prefix since only usable by server.
|
||||
}
|
||||
|
||||
public function updatenamecolor($dispatcher, &$reqData, &$out) {
|
||||
global $psdb, $psconfig, $users;
|
||||
$server = $dispatcher->findServer();
|
||||
if (!isset($psconfig['mainserver']) || !$server || $server['id'] !== $psconfig['mainserver']) {
|
||||
$out['actionerror'] = 'Access denied';
|
||||
return;
|
||||
}
|
||||
if (!isset($reqData['userid']) || !mb_strlen($users->userid($reqData['userid']))) {
|
||||
$out['actionerror'] = 'No userid was specified.';
|
||||
return;
|
||||
}
|
||||
$userid = $users->userid($reqData['userid']);
|
||||
if (!isset($reqData['source'])) {
|
||||
$out['actionerror'] = 'No color adjustment was specified.';
|
||||
return;
|
||||
}
|
||||
if (strlen($userid) > 18) {
|
||||
$out['actionerror'] = 'Usernames can only be 18 characters long';
|
||||
return;
|
||||
}
|
||||
if (!isset($reqData['by']) || !mb_strlen($users->userid($reqData['by']))) {
|
||||
$out['actionerror'] = 'Specify the action\'s actor.';
|
||||
return;
|
||||
}
|
||||
$colors = array();
|
||||
$path = realpath(__DIR__ . '/../config/colors.json');
|
||||
try {
|
||||
$data = file_get_contents($path, true);
|
||||
$colors = json_decode($data, true);
|
||||
} catch (Exception $e) {}
|
||||
$modlog_entry = '';
|
||||
if (!$reqData['source']) {
|
||||
if (!isset($colors[$userid])) {
|
||||
$out['actionerror'] = (
|
||||
'That user does not have a custom color set by the loginserver. ' .
|
||||
'Ask an admin to remove it manually if they have one.'
|
||||
);
|
||||
return;
|
||||
} else {
|
||||
unset($colors[$userid]);
|
||||
$modlog_entry = 'Username color was removed';
|
||||
}
|
||||
} else {
|
||||
$colors[$userid] = $reqData['source'];
|
||||
$modlog_entry = "Username color was set to \"{$reqData['source']}\"";
|
||||
}
|
||||
file_put_contents($path, json_encode($colors));
|
||||
|
||||
$psdb->query(
|
||||
"INSERT INTO `{$psdb->prefix}usermodlog`".
|
||||
"(`userid`, `actorid`, `date`, `ip`, `entry`) " .
|
||||
"VALUES(?, ?, ?, ?, ?)",
|
||||
[$userid, $users->userid($reqData['by']), time(), $dispatcher->getIp(), $modlog_entry]
|
||||
);
|
||||
|
||||
$out['success'] = true;
|
||||
return $out;
|
||||
}
|
||||
|
||||
public function prepreplay($dispatcher, &$reqData, &$out) {
|
||||
global $psdb, $users;
|
||||
// include_once dirname(__FILE__) . '/ntbb-ladder.lib.php'; // not clear if this is needed
|
||||
|
||||
$server = $dispatcher->findServer();
|
||||
if (!$server) {
|
||||
$out['errorip'] = $dispatcher->getIp();
|
||||
return;
|
||||
}
|
||||
if (
|
||||
// the server must be registered
|
||||
!$server ||
|
||||
// the server must send all the required values
|
||||
!isset($reqData['id']) ||
|
||||
!isset($reqData['format']) ||
|
||||
!isset($reqData['loghash']) ||
|
||||
!isset($reqData['p1']) ||
|
||||
!isset($reqData['p2']) ||
|
||||
// player usernames cannot be longer than 18 characters
|
||||
(mb_strlen($reqData['p1']) > 18) ||
|
||||
(mb_strlen($reqData['p2']) > 18) ||
|
||||
// the battle ID must be valid
|
||||
!preg_match('/^([a-z0-9]+)-[0-9]+$/', $reqData['id'], $m1) ||
|
||||
// the format ID must be valid
|
||||
!preg_match('/^([a-z0-9]+)$/', $reqData['format'], $m2) ||
|
||||
// the format from the battle ID must match the format ID
|
||||
($m1[1] !== $m2[1])) {
|
||||
$out = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
if ($server['id'] !== 'showdown') {
|
||||
$reqData['id'] = $server['id'].'-'.$reqData['id'];
|
||||
}
|
||||
$reqData['serverid'] = $server['id'];
|
||||
|
||||
include_once __DIR__.'/../replays/replays.lib.php';
|
||||
$out = $GLOBALS['Replays']->prepUpload($reqData);
|
||||
|
||||
$dispatcher->setPrefix(''); // No need for prefix since only usable by server.
|
||||
}
|
||||
|
||||
public function uploadreplay($dispatcher, &$reqData, &$out) {
|
||||
global $psdb, $users;
|
||||
|
||||
header('Content-Type: text/plain; charset=utf-8');
|
||||
|
||||
include __DIR__.'/../replays/replays.lib.php';
|
||||
die($GLOBALS['Replays']->upload($reqData));
|
||||
}
|
||||
|
||||
public function invalidatecss($dispatcher, &$reqData, &$out) {
|
||||
$server = $dispatcher->findServer();
|
||||
if (!$server) {
|
||||
$out['errorip'] = $dispatcher->getIp();
|
||||
return;
|
||||
}
|
||||
// No need to sanitise $server['id'] because it should be safe already.
|
||||
$cssfile = __DIR__ . '/../config/customcss/' . $server['id'] . '.css';
|
||||
@unlink($cssfile);
|
||||
}
|
||||
}
|
||||
|
||||
// This class should not depend on ntbb-session.lib.php.
|
||||
class LadderActionHandler {
|
||||
// There's no need to make a database query for this.
|
||||
private function getUserData($username) {
|
||||
if (!$username) $username = '';
|
||||
$userid = strtr($username, "ABCDEFGHIJKLMNOPQRSTUVWXYZ", "abcdefghijklmnopqrstuvwxyz");
|
||||
$userid = preg_replace('/[^A-Za-z0-9]+/', '', $userid);
|
||||
if (mb_strlen($userid) > 18) return false;
|
||||
return array('userid' => $userid, 'username' => $username);
|
||||
}
|
||||
|
||||
public function ladderupdate($dispatcher, &$reqData, &$out) {
|
||||
include_once dirname(__FILE__) . '/ntbb-ladder.lib.php';
|
||||
|
||||
$server = $dispatcher->findServer();
|
||||
if (!$server || $server['id'] !== 'showdown') {
|
||||
$out['errorip'] = "Your version of PS is too old for this ladder system. Please update.";
|
||||
return;
|
||||
}
|
||||
|
||||
$ladder = new NTBBLadder(@$reqData['format']);
|
||||
$p1 = $this->getUserData(@$reqData['p1']);
|
||||
$p2 = $this->getUserData(@$reqData['p2']);
|
||||
if (!$p1 || !$p2) {
|
||||
// The server should not send usernames > 18 characters long.
|
||||
$out = 0;
|
||||
return;
|
||||
}
|
||||
|
||||
$ladder->updateRating($p1, $p2, floatval($reqData['score']));
|
||||
$out['actionsuccess'] = true;
|
||||
$out['p1rating'] = $p1['rating'];
|
||||
$out['p2rating'] = $p2['rating'];
|
||||
unset($out['p1rating']['rpdata']);
|
||||
unset($out['p2rating']['rpdata']);
|
||||
$dispatcher->setPrefix(''); // No need for prefix since only usable by server.
|
||||
}
|
||||
|
||||
public function ladderget($dispatcher, &$reqData, &$out) {
|
||||
global $PokemonServers;
|
||||
include_once dirname(__FILE__) . '/ntbb-ladder.lib.php';
|
||||
|
||||
$server = @$PokemonServers[@$reqData['serverid']];
|
||||
if (!$server || $server['id'] !== 'showdown') {
|
||||
die;
|
||||
}
|
||||
|
||||
$ladder = new NTBBLadder(@$reqData['format']);
|
||||
$user = $this->getUserData(@$reqData['user']);
|
||||
if (!$user) die;
|
||||
$ladder->getAllRatings($user);
|
||||
$out = $user['ratings'];
|
||||
}
|
||||
|
||||
public function mmr($dispatcher, &$reqData, &$out) {
|
||||
global $PokemonServers;
|
||||
include_once dirname(__FILE__) . '/ntbb-ladder.lib.php';
|
||||
|
||||
$server = $dispatcher->findServer();
|
||||
if (!$server || $server['id'] !== 'showdown') {
|
||||
$out['errorip'] = "Your version of PS is too old for this ladder system. Please update.";
|
||||
return;
|
||||
}
|
||||
|
||||
$ladder = new NTBBLadder(@$reqData['format']);
|
||||
$user = $this->getUserData(@$reqData['user']);
|
||||
$out = 1000;
|
||||
if ($user) {
|
||||
$ladder->getRating($user);
|
||||
if (@$user['rating']) {
|
||||
$out = intval($user['rating']['elo']);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,40 +0,0 @@
|
|||
# -FrontPage-
|
||||
|
||||
IndexIgnore .htaccess */.??* *~ *# */HEADER* */README* */_vti*
|
||||
|
||||
<Limit GET POST>
|
||||
order deny,allow
|
||||
deny from all
|
||||
allow from all
|
||||
</Limit>
|
||||
<Limit PUT DELETE>
|
||||
order deny,allow
|
||||
deny from all
|
||||
</Limit>
|
||||
|
||||
AddType text/plain .phps
|
||||
AddType application/x-tgz .tgz
|
||||
AddType application/x-chrome-extension .crx
|
||||
AddType application/x-web-app-manifest+json .webapp
|
||||
|
||||
<IfModule mod_rewrite.c>
|
||||
RewriteEngine on
|
||||
|
||||
RewriteCond %{HTTP:X-Forwarded-Proto} ^http$
|
||||
RewriteRule ^(.*)$ https://replay.pokemonshowdown.com/$1 [R=302,NE,L]
|
||||
|
||||
RewriteRule ^replay\/(.*)$ /$1 [R=302,L]
|
||||
|
||||
RewriteRule ^battle-([A-Za-z0-9-]+)?$ /$1 [R=302,L]
|
||||
|
||||
RewriteRule ^search/?$ search.php [L,QSA]
|
||||
RewriteRule ^search\.json$ search.json.php [L,QSA]
|
||||
RewriteRule ^([A-Za-z0-9-]+)$ battle.php?name=$1 [L,QSA]
|
||||
RewriteRule ^([A-Za-z0-9-]+)/manage$ battle.php?name=$1&manage [L,QSA]
|
||||
RewriteRule ^([A-Za-z0-9-]+)\.log$ battle.log.php?name=$1 [L,QSA]
|
||||
RewriteRule ^([A-Za-z0-9-]+)\.json$ battle.log.php?json&name=$1 [L,QSA]
|
||||
|
||||
RewriteCond %{REQUEST_FILENAME} !-f
|
||||
RewriteRule ^(apple-touch-icon-precomposed\.png)$ - [R=404,L]
|
||||
|
||||
</IfModule>
|
||||
|
|
@ -1,46 +0,0 @@
|
|||
<?php
|
||||
|
||||
error_reporting(0);
|
||||
|
||||
header('HTTP/1.1 404 Not Found');
|
||||
|
||||
include_once 'theme/panels.lib.php';
|
||||
|
||||
$page = '404';
|
||||
$pageTitle = "Replay not found";
|
||||
|
||||
$panels->setPageTitle("Replay not found");
|
||||
$panels->noScripts();
|
||||
$panels->start();
|
||||
|
||||
?>
|
||||
<div class="pfx-panel"><div class="pfx-body pfx-body-padded" style="max-width:8in;">
|
||||
<div class="main">
|
||||
|
||||
<h1>Not Found</h1>
|
||||
<p>
|
||||
The battle you're looking for has expired. Battles expire after 15 minutes of inactivity unless they're saved.
|
||||
</p>
|
||||
<p>
|
||||
In the future, remember to click <strong>Upload and share replay</strong> to save a replay permanently.
|
||||
</p>
|
||||
|
||||
<script type="text/javascript"><!--
|
||||
google_ad_client = "ca-pub-6535472412829264";
|
||||
/* PS replay */
|
||||
google_ad_slot = "8206205605";
|
||||
google_ad_width = 728;
|
||||
google_ad_height = 90;
|
||||
//-->
|
||||
</script>
|
||||
<script type="text/javascript"
|
||||
src="//pagead2.googlesyndication.com/pagead/show_ads.js">
|
||||
</script>
|
||||
|
||||
</div>
|
||||
</div></div>
|
||||
<?php
|
||||
|
||||
$panels->end();
|
||||
|
||||
?>
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
<?php
|
||||
|
||||
error_reporting(0);
|
||||
|
||||
header('HTTP/1.1 503 Service Unavailable');
|
||||
|
||||
include_once 'theme/panels.lib.php';
|
||||
|
||||
$page = '503';
|
||||
$pageTitle = "Service Unavailable";
|
||||
|
||||
$panels->setPageTitle("Replay not found");
|
||||
$panels->noScripts();
|
||||
$panels->start();
|
||||
|
||||
?>
|
||||
<div class="pfx-panel"><div class="pfx-body pfx-body-padded" style="max-width:8in;">
|
||||
<div class="main">
|
||||
|
||||
<h1>Technical difficulties</h1>
|
||||
<p>
|
||||
<?= @$Replays->offlineReason ? $Replays->offlineReason : "We're currently experiencing some technical difficulties. Please try again later. Sorry." ?>
|
||||
</p>
|
||||
|
||||
<script type="text/javascript"><!--
|
||||
google_ad_client = "ca-pub-6535472412829264";
|
||||
/* PS replay */
|
||||
google_ad_slot = "8206205605";
|
||||
google_ad_width = 728;
|
||||
google_ad_height = 90;
|
||||
//-->
|
||||
</script>
|
||||
<script type="text/javascript"
|
||||
src="//pagead2.googlesyndication.com/pagead/show_ads.js">
|
||||
</script>
|
||||
|
||||
</div>
|
||||
</div></div>
|
||||
<?php
|
||||
|
||||
$panels->end();
|
||||
|
||||
?>
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 44 KiB |
|
|
@ -1,48 +0,0 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/**
|
||||
* This script parses index.html and sets the version query string of each
|
||||
* resource to be the MD5 hash of that resource.
|
||||
*/
|
||||
|
||||
const fs = require('fs');
|
||||
const crypto = require('crypto');
|
||||
|
||||
process.chdir(__dirname);
|
||||
|
||||
function updateIndex() {
|
||||
let indexContents = fs.readFileSync('theme/wrapper.inc.template.php', {encoding: 'utf8'});
|
||||
|
||||
// add hashes to js and css files
|
||||
process.stdout.write("Updating hashes... ");
|
||||
// Check for <script, <link or <img so we don't add useless hashes to <a
|
||||
indexContents = indexContents.replace(/(<script[^>]+?src|<link[^>]+?href|<img[^>]+?src)="\/(.*?)(\?[a-z0-9]*?)?"/g, runReplace);
|
||||
console.log("DONE");
|
||||
|
||||
process.stdout.write("Writing new `wrapper.inc.php` file... ");
|
||||
fs.writeFileSync('theme/wrapper.inc.php', indexContents);
|
||||
console.log("DONE");
|
||||
}
|
||||
|
||||
function runReplace(a, b, c) {
|
||||
let hash = Math.random(); // just in case creating the hash fails
|
||||
const routes = JSON.parse(fs.readFileSync('../config/routes.json'));
|
||||
try {
|
||||
var filepath = c;
|
||||
if (c.includes('/' + routes.client + '/')) {
|
||||
const filename = c.replace('/' + routes.client + '/', '');
|
||||
filepath = '../' + filename;
|
||||
}
|
||||
const fstr = fs.readFileSync(filepath, {encoding: 'utf8'});
|
||||
hash = crypto.createHash('md5').update(fstr).digest('hex').substr(0, 8);
|
||||
} catch (e) {}
|
||||
c = c.replace('/replay.pokemonshowdown.com/', '/' + routes.replays + '/');
|
||||
c = c.replace('/dex.pokemonshowdown.com/', '/' + routes.dex + '/');
|
||||
c = c.replace('/play.pokemonshowdown.com/', '/' + routes.client + '/');
|
||||
c = c.replace('/pokemonshowdown.com/users/', '/' + routes.users + '/');
|
||||
c = c.replace('/pokemonshowdown.com/', '/' + routes.root + '/');
|
||||
|
||||
return b + '="/' + c + '?' + hash + '"';
|
||||
}
|
||||
|
||||
updateIndex();
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 318 B |
|
|
@ -1,246 +0,0 @@
|
|||
<?php
|
||||
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', TRUE);
|
||||
ini_set('display_startup_errors', TRUE);
|
||||
|
||||
include 'theme/panels.lib.php';
|
||||
// require_once '../../pokemonshowdown.com/lib/ntbb-database.lib.php';
|
||||
require_once __DIR__ . '/../config/servers.inc.php';
|
||||
|
||||
$panels->setPageTitle('Replays');
|
||||
$panels->setPageDescription('Watch replays of battles on Pokémon Showdown!');
|
||||
$panels->setTab('replay');
|
||||
$panels->start();
|
||||
?>
|
||||
<div class="pfx-panel"><div class="pfx-body pfx-body-padded">
|
||||
<h1>Upload replays</h1>
|
||||
<p>
|
||||
To upload a replay, click "Share" or use the command <code>/savereplay</code> in a Pokémon Showdown battle!
|
||||
</p>
|
||||
<h1>Search replays</h1>
|
||||
<!--p>Username search temporarily down, will be back up soon</p-->
|
||||
<form action="/search/" method="get" data-target="replace">
|
||||
<p style="text-align:center">
|
||||
<label><input type="text" name="user" class="textbox" placeholder="Username" size="24" /></label>
|
||||
<button type="submit"><strong>Search for user</strong></button>
|
||||
</p>
|
||||
</form>
|
||||
<form action="/search/" method="get" data-target="replace">
|
||||
<p style="text-align:center">
|
||||
<label><input type="text" name="format" class="textbox" placeholder="Format" size="24" /></label>
|
||||
<button type="submit"><strong>Search by format</strong></button>
|
||||
</p>
|
||||
</form>
|
||||
<h1>Featured replays</h1>
|
||||
<ul class="linklist" style="max-width:480px;margin:0 auto;text-align:center">
|
||||
<h3>Fun</h3>
|
||||
<li><a href="/oumonotype-82345404" data-target="push">
|
||||
<small>[oumonotype]<br /></small>
|
||||
<strong>kdarewolf</strong> vs. <strong>Onox</strong>
|
||||
<small><br />Protean + prediction</small>
|
||||
</a></li>
|
||||
<li><a href="/anythinggoes-218380995" data-target="push">
|
||||
<small>[anythinggoes]<br /></small>
|
||||
<strong>Anta2</strong> vs. <strong>dscottnew</strong>
|
||||
<small><br />Cheek Pouch</small>
|
||||
</a></li>
|
||||
<li><a href="/uberssuspecttest-147833524" data-target="push">
|
||||
<small>[ubers]<br /></small>
|
||||
<strong>Metal Brellow</strong> vs. <strong>zig100</strong>
|
||||
<small><br />Topsy-Turvy</small>
|
||||
</a></li>
|
||||
<li><button class="button" onclick="$('.older2').show();$(this).parent().hide()">Older</button></li>
|
||||
<li class="older2" style="display:none"><a href="/smogondoubles-75588440" data-target="push">
|
||||
<small>[smogondoubles]<br /></small>
|
||||
<strong>jamace6</strong> vs. <strong>DubsWelder</strong>
|
||||
<small><br />Garchomp sweeps 11 pokemon</small>
|
||||
</a></li>
|
||||
<li class="older2" style="display:none"><a href="/ou-20651579" data-target="push">
|
||||
<small>[ou]<br /></small>
|
||||
<strong>RainSeven07</strong> vs. <strong>my body is regi</strong>
|
||||
<small><br />An entire team based on Assist V-create</small>
|
||||
</a></li>
|
||||
<li class="older2" style="display:none"><a href="/balancedhackmons7322360" data-target="push">
|
||||
<small>[balancedhackmons]<br /></small>
|
||||
<strong>a ver</strong> vs. <strong>Shuckie</strong>
|
||||
<small><br />To a ver's frustration, PP stall is viable in Balanced Hackmons</small>
|
||||
</a></li>
|
||||
<h3>Competitive</h3>
|
||||
<li><a href="/doublesou-232753081" data-target="push" style="white-space:normal">
|
||||
<small>[doubles ou]<br /></small>
|
||||
<strong>Electrolyte</strong> vs. <strong>finally</strong>
|
||||
<small><br />finally steals Electrolyte's spot in the finals of the Doubles Winter Seasonal by outplaying Toxic Aegislash.</small>
|
||||
</a></li>
|
||||
<li><a href="/smogtours-gen5ou-59402" data-target="push" style="white-space:normal">
|
||||
<small>[bw ou]<br /></small>
|
||||
<strong>Reymedy</strong> vs. <strong>Leftiez</strong>
|
||||
<small><br />Reymedy's superior grasp over BW OU lead to his claim of victory over Leftiez in the No Johns Tournament.</small>
|
||||
</a></li>
|
||||
<li><a href="/smogtours-gen3ou-56583" data-target="push" style="white-space:normal">
|
||||
<small>[adv ou]<br /></small>
|
||||
<strong>pokebasket</strong> vs. <strong>Alf'</strong>
|
||||
<small><br />pokebasket proved Blissey isn't really one to take a Focus Punch well in his victory match over Alf' in the Fuck Trappers ADV OU tournament.</small>
|
||||
</a></li>
|
||||
<li><a href="/smogtours-ou-55891" data-target="push" style="white-space:normal">
|
||||
<small>[oras ou]<br /></small>
|
||||
<strong>Marshall.Law</strong> vs. <strong>Malekith</strong>
|
||||
<small><br />In a "match full of reverses", Marshall.Law takes on Malekith in the finals of It's No Use.</small>
|
||||
</a></li>
|
||||
<li><a href="/smogtours-ubers-54583" data-target="push" style="white-space:normal">
|
||||
<small>[custom]<br /></small>
|
||||
<strong>hard</strong> vs. <strong>panamaxis</strong>
|
||||
<small><br />Dark horse panamaxis proves his worth as the rightful winner of The Walkthrough Tournament in this exciting final versus hard.</small>
|
||||
</a></li>
|
||||
<li><button class="button" onclick="$('.older1').show();$(this).parent().hide()">Older</button></li>
|
||||
<li class="older1" style="display:none"><a href="/smogtours-ubers-34646" data-target="push" style="white-space:normal">
|
||||
<small>[oras ubers]<br /></small>
|
||||
<strong>steelphoenix</strong> vs. <strong>Jibaku</strong>
|
||||
<small><br />In this SPL Week 4 battle, Jibaku's clever plays with Mega Sableye keep the momentum mostly in his favor.</small>
|
||||
</a></li>
|
||||
<li class="older1" style="display:none"><a href="/smogtours-uu-36860" data-target="push" style="white-space:normal">
|
||||
<small>[oras uu]<br /></small>
|
||||
<strong>IronBullet93</strong> vs. <strong>Laurel</strong>
|
||||
<small><br />Laurel outplays IronBullet's Substitute Tyrantrum with the sly use of a Shuca Berry Cobalion, but luck was inevitably the deciding factor in this SPL Week 6 match.</small>
|
||||
</a></li>
|
||||
<li class="older1" style="display:none"><a href="/smogtours-gen5ou-36900" data-target="push" style="white-space:normal">
|
||||
<small>[bw ou]<br /></small>
|
||||
<strong>Lowgock</strong> vs. <strong>Meridian</strong>
|
||||
<small><br />This SPL Week 6 match features impressive plays, from Jirachi sacrificing itself to paralysis to avoid a burn to some clever late-game switches.</small>
|
||||
</a></li>
|
||||
<li class="older1" style="display:none"><a href="/smogtours-gen4ou-36782" data-target="push" style="white-space:normal">
|
||||
<small>[dpp ou]<br /></small>
|
||||
<strong>Heist</strong> vs. <strong>liberty32</strong>
|
||||
<small><br />Starting out as an entry hazard-filled stallfest, this close match is eventually decided by liberty32's efficient use of Aerodactyl.</small>
|
||||
</a></li>
|
||||
<li class="older1" style="display:none"><a href="/randombattle-213274483" data-target="push" style="white-space:normal">
|
||||
<small>[randombattle]<br /></small>
|
||||
<strong>The Immortal</strong> vs. <strong>Amphinobite</strong>
|
||||
<small><br />Substitute Lugia and Rotom-Fan take advantage of Slowking's utility and large HP stat, respectively, in this high ladder match.</small>
|
||||
</a></li>
|
||||
</ul>
|
||||
<h1>Recent replays</h1>
|
||||
<ul class="linklist" style="max-width:480px;margin:0 auto;text-align:center">
|
||||
<?php
|
||||
|
||||
// $replays = [];
|
||||
// echo "<p>";
|
||||
// echo "Recent replays are currently unavailable due to database load. They'll be back very soon!";
|
||||
// echo "</p>";
|
||||
|
||||
require_once 'replays.lib.php';
|
||||
|
||||
if (!$Replays->db) {
|
||||
echo "<p>";
|
||||
echo @$Replays->offlineReason ? $Replays->offlineReason : "Replays are currently offline due to technical difficulties. We'll be back up soon!";
|
||||
echo "</p>";
|
||||
} else {
|
||||
|
||||
$replays = $Replays->recent();
|
||||
|
||||
$time = time();
|
||||
$timeoffset = 60;
|
||||
|
||||
foreach ($replays as $replay) {
|
||||
$timetext = '';
|
||||
while ($timeoffset >= 0 && $replay['uploadtime'] < $time - $timeoffset) {
|
||||
switch ($timeoffset) {
|
||||
case 60:
|
||||
$timetext = '<h3>1 minute ago</h3>';
|
||||
$timeoffset = 120;
|
||||
break;
|
||||
case 120:
|
||||
$timetext = '<h3>2 minutes ago</h3>';
|
||||
$timeoffset = 180;
|
||||
break;
|
||||
case 180:
|
||||
$timetext = '<h3>3 minutes ago</h3>';
|
||||
$timeoffset = 240;
|
||||
break;
|
||||
case 240:
|
||||
$timetext = '<h3>4 minutes ago</h3>';
|
||||
$timeoffset = 300;
|
||||
break;
|
||||
case 300:
|
||||
$timetext = '<h3>5 minutes ago</h3>';
|
||||
$timeoffset = 600;
|
||||
break;
|
||||
case 600:
|
||||
$timetext = '<h3>10 minutes ago</h3>';
|
||||
$timeoffset = 1200;
|
||||
break;
|
||||
case 1200:
|
||||
$timetext = '<h3>20 minutes ago</h3>';
|
||||
$timeoffset = 1800;
|
||||
break;
|
||||
case 1800:
|
||||
$timetext = '<h3>30 minutes ago</h3>';
|
||||
$timeoffset = 3600;
|
||||
break;
|
||||
case 3600:
|
||||
$timetext = '<h3>1-2 hours ago</h3>';
|
||||
$timeoffset = 2*3600;
|
||||
break;
|
||||
case 2*3600:
|
||||
$timetext = '<h3>2-3 hours ago</h3>';
|
||||
$timeoffset = 3*3600;
|
||||
break;
|
||||
case 3*3600:
|
||||
$timetext = '<h3>3-4 hours ago</h3>';
|
||||
$timeoffset = 4*3600;
|
||||
break;
|
||||
case 4*3600:
|
||||
$timetext = '<h3>4-8 hours ago</h3>';
|
||||
$timeoffset = 8*3600;
|
||||
break;
|
||||
case 8*3600:
|
||||
$timetext = '<h3>8-12 hours ago</h3>';
|
||||
$timeoffset = 12*3600;
|
||||
break;
|
||||
case 12*3600:
|
||||
$timetext = '<h3>12-24 hours ago</h3>';
|
||||
$timeoffset = 24*3600;
|
||||
break;
|
||||
case 24*3600:
|
||||
$timetext = '<h3>1-2 days ago</h3>';
|
||||
$timeoffset = 2*24*3600;
|
||||
break;
|
||||
case 2*24*3600:
|
||||
$timetext = '<h3>2-3 days ago</h3>';
|
||||
$timeoffset = 3*24*3600;
|
||||
break;
|
||||
case 3*24*3600:
|
||||
$timetext = '<h3>3 days ago</h3>';
|
||||
$timeoffset = 5*24*3600;
|
||||
break;
|
||||
default:
|
||||
$timeoffset = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
echo $timetext;
|
||||
$server = '';
|
||||
if (preg_match('/^([a-z0-9]+)-[a-z0-9]+-[0-9]+$/', $replay['id'], $matches)) {
|
||||
$serverid = $matches[1];
|
||||
if (!isset($PokemonServers[$serverid])) {
|
||||
// This should be impossible.
|
||||
$server = 'unknown server';
|
||||
} else {
|
||||
$server = strtolower($PokemonServers[$serverid]['name']);
|
||||
}
|
||||
}
|
||||
?>
|
||||
<li><a href="/<?php echo htmlspecialchars($replay['id']); ?>" data-target="push"><small>[<?php echo htmlspecialchars($replay['format']); ?><?php if ($server) echo ' - ' . htmlspecialchars($server) ?>]<br /></small> <strong><?php echo htmlspecialchars($replay['p1']); ?></strong> vs. <strong><?php echo htmlspecialchars($replay['p2']); ?></strong></a></li>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
</ul>
|
||||
</div></div>
|
||||
|
||||
<?php
|
||||
|
||||
$panels->end();
|
||||
|
||||
?>
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
|
@ -1,51 +0,0 @@
|
|||
<?php
|
||||
|
||||
$username = @$_REQUEST['user'];
|
||||
$username2 = @$_REQUEST['user2'];
|
||||
$format = @$_REQUEST['format'];
|
||||
$contains = (@$_REQUEST['contains']);
|
||||
$byRating = isset($_REQUEST['rating']);
|
||||
$isPrivate = isset($_REQUEST['private']);
|
||||
|
||||
header('Content-Type: application/json');
|
||||
if (!$isPrivate) header('Access-Control-Allow-Origin: *');
|
||||
|
||||
require_once 'replays.lib.php';
|
||||
include_once '../lib/ntbb-session.lib.php';
|
||||
|
||||
$username = $users->userid($username);
|
||||
$isPrivateAllowed = ($username === $curuser['userid'] || $curuser['userid'] === 'zarel');
|
||||
if ($isPrivate && !$isPrivateAllowed) {
|
||||
die('"ERROR: access denied"');
|
||||
}
|
||||
|
||||
$page = intval($_REQUEST['page'] ?? 0);
|
||||
|
||||
$replays = null;
|
||||
if ($page > 25) {
|
||||
die('"ERROR: page limit is 25"');
|
||||
} else if ($username || $format) {
|
||||
$replays = $Replays->search([
|
||||
"username" => $username,
|
||||
"username2" => $username2,
|
||||
"format" => $format,
|
||||
"byRating" => $byRating,
|
||||
"isPrivate" => $isPrivate,
|
||||
"page" => $page
|
||||
]);
|
||||
} else if ($contains) {
|
||||
$replays = $Replays->fullSearch($contains, $page);
|
||||
} else {
|
||||
$replays = $Replays->recent();
|
||||
}
|
||||
|
||||
if ($replays) {
|
||||
foreach ($replays as &$replay) {
|
||||
if ($replay['password'] ?? null) {
|
||||
$replay['id'] .= '-' . $replay['password'];
|
||||
}
|
||||
unset($replay['password']);
|
||||
}
|
||||
}
|
||||
|
||||
echo json_encode($replays);
|
||||
|
|
@ -1,277 +0,0 @@
|
|||
<?php
|
||||
|
||||
error_reporting(E_ALL);
|
||||
ini_set('display_errors', TRUE);
|
||||
ini_set('display_startup_errors', TRUE);
|
||||
|
||||
include 'theme/panels.lib.php';
|
||||
|
||||
$username = @$_REQUEST['user'];
|
||||
$format = ($username ? '' : @$_REQUEST['format']);
|
||||
$contains = (@$_REQUEST['contains']);
|
||||
$byRating = isset($_REQUEST['rating']);
|
||||
$isPrivate = isset($_REQUEST['private']);
|
||||
|
||||
$noRequest = (!$username && !$format && !$contains);
|
||||
if (!$noRequest) {
|
||||
header('Cache-Control: max-age=0, no-cache, no-store, must-revalidate');
|
||||
}
|
||||
|
||||
if ($username) {
|
||||
$panels->setPageTitle($username."'s replays");
|
||||
} else if ($format) {
|
||||
$panels->setPageTitle($username." replays");
|
||||
} else {
|
||||
$panels->setPageTitle("Search replays");
|
||||
}
|
||||
$panels->setTab('replay');
|
||||
$panels->start();
|
||||
|
||||
$page = 0;
|
||||
if (@$_REQUEST['page']) $page = intval($_REQUEST['page']);
|
||||
|
||||
if (!$page) {
|
||||
?>
|
||||
<div class="pfx-panel"><div class="pfx-body pfx-body-padded">
|
||||
<?php
|
||||
if (!$contains) {
|
||||
?>
|
||||
<h1>Search replays</h1>
|
||||
<form action="/search/" method="get" data-target="replace">
|
||||
<p style="text-align:center">
|
||||
<label><input type="text" name="user" class="textbox" placeholder="Username" size="24"<?= !$format ? ' autofocus="autofocus"' : '' ?> value="<?php echo htmlspecialchars($username) ?>" /></label>
|
||||
<button type="submit"><strong>Search</strong></button>
|
||||
</p>
|
||||
</form>
|
||||
<form action="/search/" method="get" data-target="replace">
|
||||
<p style="text-align:center">
|
||||
<label><input type="text" name="format" class="textbox" placeholder="Format" size="24"<?= $format ? ' autofocus="autofocus"' : '' ?> value="<?php echo htmlspecialchars($format) ?>" /></label>
|
||||
<button type="submit"><strong>Search</strong></button>
|
||||
</p>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
if ($noRequest || $contains) {
|
||||
?>
|
||||
<h1>Experimental full-text search</h1>
|
||||
<form action="/search/" method="get" data-target="replace">
|
||||
<p style="text-align:center">
|
||||
<label><input type="text" name="contains" class="textbox" placeholder="EXPERIMENTAL FULL TEXT SEARCH" size="24"<?= $format ? ' autofocus="autofocus"' : '' ?> value="<?php echo htmlspecialchars($contains) ?>" /></label>
|
||||
<button type="submit"><strong>Search</strong></button>
|
||||
</p>
|
||||
</form>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
if ($username || $format || $contains) {
|
||||
require_once 'replays.lib.php';
|
||||
include_once '../lib/ntbb-session.lib.php';
|
||||
|
||||
$username = $users->userid($username);
|
||||
$isPrivateAllowed = ($username === $curuser['userid'] || $curuser['userid'] === 'zarel');
|
||||
|
||||
if (!$page) {
|
||||
?>
|
||||
<h1>Search results for "<?php echo htmlspecialchars($username ? $username : ($contains ? $contains : $format)); ?>"</h1>
|
||||
<?php
|
||||
if ($format) {
|
||||
$format = $Replays->toID($format);
|
||||
?>
|
||||
<ul class="tabbar centered" style="margin-bottom: 18px"><li><a class="button nav-first<?= $byRating ? '' : ' cur' ?>" href="/search/?format=<?= $format ?>" data-target="replace">Newest</a></li><li><a class="button nav-last<?= $byRating ? ' cur' : '' ?>" href="/search/?format=<?= $format ?>&rating" data-target="replace">Highest rated</a></li></ul>
|
||||
<?php
|
||||
} else if ($isPrivateAllowed) {
|
||||
?>
|
||||
<ul class="tabbar centered" style="margin-bottom: 18px"><li><a class="button nav-first<?= $isPrivate ? '' : ' cur' ?>" href="/search/?user=<?= $username ?>" data-target="replace">Public</a></li><li><a class="button nav-last<?= $isPrivate ? ' cur' : '' ?>" href="/search/?user=<?= $username ?>&private" data-target="replace">Private</a></li></ul>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
<ul class="linklist" style="max-width:480px;margin:0 auto;text-align:center">
|
||||
<?php
|
||||
}
|
||||
|
||||
$replays = null;
|
||||
if ($page > 25) {
|
||||
// no
|
||||
} else if ($username) {
|
||||
if (!$isPrivate || $isPrivateAllowed) {
|
||||
$replays = $Replays->search(["username" => $username, "isPrivate" => $isPrivate, "page" => $page]);
|
||||
}
|
||||
} else if ($contains) {
|
||||
$replays = $Replays->fullSearch($contains, $page);
|
||||
} else {
|
||||
$replays = $Replays->search(["format" => $format, "byRating" => $byRating, "page" => $page]);
|
||||
}
|
||||
|
||||
$time = time();
|
||||
$timeoffset = 600;
|
||||
$count = 0;
|
||||
|
||||
// $newoffset = 0;
|
||||
if ($isPrivate && !$isPrivateAllowed) {
|
||||
?>
|
||||
<li>Error: You must be logged into account "<?= htmlspecialchars($username) ?>" to see their private replays (You're currently "<?= $curuser['userid'] ?>").</li>
|
||||
<?php
|
||||
} else if (!$replays || !count($replays)) {
|
||||
if ($page > 25) {
|
||||
?>
|
||||
<li>Can't search any further back</li>
|
||||
<?php
|
||||
} else if (!$Replays->db) {
|
||||
?>
|
||||
<li><?= $Replays->offlineReason ?></li>
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<li>No results found</li>
|
||||
<?php
|
||||
}
|
||||
} else foreach ($replays as $replay) {
|
||||
if ($count == 50) {
|
||||
$count++;
|
||||
// $newoffset = $replay['num'];
|
||||
break;
|
||||
}
|
||||
$timetext = '';
|
||||
if (!$byRating) while ($timeoffset >= 0 && $replay['uploadtime'] < $time - $timeoffset) {
|
||||
$prevtimeoffset = $timeoffset;
|
||||
switch ($timeoffset) {
|
||||
case 600:
|
||||
$timetext = '<h3>10 minutes ago</h3>';
|
||||
$timeoffset = 1200;
|
||||
break;
|
||||
case 1200:
|
||||
$timetext = '<h3>20 minutes ago</h3>';
|
||||
$timeoffset = 1800;
|
||||
break;
|
||||
case 1800:
|
||||
$timetext = '<h3>30 minutes ago</h3>';
|
||||
$timeoffset = 3600;
|
||||
break;
|
||||
case 3600:
|
||||
$timetext = '<h3>1-2 hours ago</h3>';
|
||||
$timeoffset = 2*3600;
|
||||
break;
|
||||
case 2*3600:
|
||||
$timetext = '<h3>2-3 hours ago</h3>';
|
||||
$timeoffset = 3*3600;
|
||||
break;
|
||||
case 3*3600:
|
||||
$timetext = '<h3>3-4 hours ago</h3>';
|
||||
$timeoffset = 4*3600;
|
||||
break;
|
||||
case 4*3600:
|
||||
$timetext = '<h3>4-8 hours ago</h3>';
|
||||
$timeoffset = 8*3600;
|
||||
break;
|
||||
case 8*3600:
|
||||
$timetext = '<h3>8-12 hours ago</h3>';
|
||||
$timeoffset = 12*3600;
|
||||
break;
|
||||
case 12*3600:
|
||||
$timetext = '<h3>12-24 hours ago</h3>';
|
||||
$timeoffset = 24*3600;
|
||||
break;
|
||||
case 24*3600:
|
||||
$timetext = '<h3>1-2 days ago</h3>';
|
||||
$timeoffset = 2*24*3600;
|
||||
break;
|
||||
case 2*24*3600:
|
||||
$timetext = '<h3>2-3 days ago</h3>';
|
||||
$timeoffset = 3*24*3600;
|
||||
break;
|
||||
case 3*24*3600:
|
||||
$timetext = '<h3>3-7 days ago</h3>';
|
||||
$timeoffset = 7*24*3600;
|
||||
break;
|
||||
case 7*24*3600:
|
||||
$timetext = '<h3>1 week ago</h3>';
|
||||
$timeoffset = 14*24*3600;
|
||||
break;
|
||||
case 14*24*3600:
|
||||
$timetext = '<h3>2 weeks ago</h3>';
|
||||
$timeoffset = 21*24*3600;
|
||||
break;
|
||||
case 21*24*3600:
|
||||
$timetext = '<h3>3 weeks ago</h3>';
|
||||
$timeoffset = 30*24*3600;
|
||||
break;
|
||||
case 30*24*3600:
|
||||
$timetext = '<h3>1 month ago</h3>';
|
||||
$timeoffset = 2*30*24*3600;
|
||||
break;
|
||||
case 2*30*24*3600:
|
||||
$timetext = '<h3>2 months ago</h3>';
|
||||
$timeoffset = 3*30*24*3600;
|
||||
break;
|
||||
case 3*30*24*3600:
|
||||
$timetext = '<h3>3-6 months ago</h3>';
|
||||
$timeoffset = 183*24*3600;
|
||||
break;
|
||||
case 183*24*3600:
|
||||
$timetext = '<h3>6-9 months ago</h3>';
|
||||
$timeoffset = 274*24*3600;
|
||||
break;
|
||||
case 274*24*3600:
|
||||
$timetext = '<h3>9-12 months ago</h3>';
|
||||
$timeoffset = 365*24*3600;
|
||||
break;
|
||||
case 365*24*3600:
|
||||
$timetext = '<h3>more than 1 year ago</h3>';
|
||||
$timeoffset = 2*365*24*3600;
|
||||
break;
|
||||
case 2*365*24*3600:
|
||||
$timetext = '<h3>more than 2 year ago</h3>';
|
||||
$timeoffset = 3*365*24*3600;
|
||||
break;
|
||||
case 3*365*24*3600:
|
||||
$timetext = '<h3>more than 3 years ago</h3>';
|
||||
$timeoffset = 4*365*24*3600;
|
||||
break;
|
||||
case 4*365*24*3600:
|
||||
$timetext = '<h3>more than 4 years ago</h3>';
|
||||
$timeoffset = 5*365*24*3600;
|
||||
break;
|
||||
case 5*365*24*3600:
|
||||
$timetext = '<h3>more than 5 years ago</h3>';
|
||||
$timeoffset = -1;
|
||||
break;
|
||||
}
|
||||
if ($prevtimeoffset === $timeoffset) break;
|
||||
}
|
||||
echo $timetext;
|
||||
$replayid = $replay['id'];
|
||||
if ($replay['password'] ?? null) $replayid .= '-' . $replay['password'] . 'pw';
|
||||
?>
|
||||
<li><a href="/<?php echo $replayid; ?>" data-target="push"><small>[<?php echo $replay['format']; ?>]<?php if (@$replay['rating']) echo ' rating: '.$replay['rating']; ?><br /></small> <strong><?php echo htmlspecialchars($replay['p1']); ?></strong> vs. <strong><?php echo htmlspecialchars($replay['p2']); ?></strong></a></li>
|
||||
<?php
|
||||
$count++;
|
||||
}
|
||||
|
||||
if (!$page) {
|
||||
?>
|
||||
</ul>
|
||||
<?php
|
||||
if ($count === 51) {
|
||||
?>
|
||||
<p style="text-align: center"><button class="button" name="moreResults" value="<?= /* $newoffset */ '' ?>" data-user="<?= htmlspecialchars($username) ?>" data-format="<?= htmlspecialchars($format) ?>" data-private="<?= $isPrivate ? '1' : '' ?>">More<br /><i class="fa fa-caret-down"></i></button></p>
|
||||
<?php
|
||||
}
|
||||
} else {
|
||||
// echo '<input type="hidden" name="offset" class="offset" value="' . $newoffset . '" />';
|
||||
if ($count === 51) {
|
||||
echo '<input type="hidden" name="more" class="more" value="1" />';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$page) {
|
||||
?>
|
||||
</div></div>
|
||||
|
||||
<?php
|
||||
}
|
||||
|
||||
$panels->end();
|
||||
|
||||
?>
|
||||
Loading…
Reference in New Issue
Block a user