예제 #1
0
function GetReagents($spell)
{
    $cacheFile = __DIR__ . '/reagents.cache/' . $spell . '.json';
    if (file_exists($cacheFile)) {
        return json_decode(file_get_contents($cacheFile), true);
    }
    $power = \Newsstand\HTTP::Get(sprintf('http://www.wowhead.com/spell=%d&power', $spell));
    if (!$power) {
        DebugMessage("Spell {$spell} could not be fetched from Wowhead.", E_USER_NOTICE);
        return false;
    }
    $reagents = [];
    $c = preg_match('/Reagents:<br[^>]*><div\\b[^>]*>([\\w\\W]+?)<\\/div>/', $power, $res);
    if ($c > 0) {
        $itemsHtml = $res[1];
        $c = preg_match_all('/<a href="\\/item=(\\d+)">[^<]*<\\/a>(?:&nbsp;\\((\\d+)\\))?/', $itemsHtml, $res);
        for ($x = 0; $x < $c; $x++) {
            $itemId = $res[1][$x];
            $qty = intval($res[2][$x]);
            if (!$qty) {
                $qty = 1;
            }
            if (!isset($reagents[$itemId])) {
                $reagents[$itemId] = 0;
            }
            $reagents[$itemId] += $qty;
        }
    } else {
        DebugMessage("Spell {$spell} has no reagents.", E_USER_NOTICE);
    }
    file_put_contents($cacheFile, json_encode($reagents, JSON_NUMERIC_CHECK));
    return $reagents;
}
예제 #2
0
function BuildItemDefs()
{
    $itemDB2 = new Reader(__DIR__ . '/../DBC/current/enUS/Item.db2');
    $ids = $itemDB2->getIds();
    unset($itemDB2);
    $idMap = [];
    foreach ($ids as $id) {
        $idMap[$id] = $id;
    }
    DebugMessage("Item ID count: " . count($idMap));
    $sparseDB2 = new Reader(__DIR__ . '/../DBC/current/enUS/Item-sparse.db2', [13, 14, 15, 16, 17]);
    $ids = $sparseDB2->getIds();
    unset($sparseDB2);
    DebugMessage("Sparse ID count: " . count($ids));
    foreach ($ids as $id) {
        unset($idMap[$id]);
    }
    DebugMessage("Missing ID count: " . count($idMap));
    if (!count($idMap)) {
        return false;
    }
    $idMap = array_reverse($idMap);
    reset($idMap);
    $lastId = current($idMap);
    DebugMessage("Last item ID: {$lastId}");
    $lua = "local addonName, addonTable = ...\n";
    $lua .= "addonTable.missingItems = {" . implode(',', $idMap) . "}\n";
    return $lua;
}
예제 #3
0
function AddHourlyData()
{
    global $db, $caughtKill;
    if ($caughtKill) {
        return;
    }
    $sqlPattern = <<<'EOF'
insert into tblSellerHistoryHourly (seller, `when`, `new%1$s`, `total%1$s`)
(select seller, date(`snapshot`), `new`, `total` 
from tblSellerHistory
where hour(`snapshot`) = %2$d
order by `snapshot`
)
on duplicate key update `new%1$s` = values(`new%1$s`), `total%1$s` = values(`total%1$s`)
EOF;
    for ($hour = 0; $hour < 24; $hour++) {
        heartbeat();
        if ($caughtKill) {
            break;
        }
        $hourPadded = str_pad($hour, 2, '0', STR_PAD_LEFT);
        $sql = sprintf($sqlPattern, $hourPadded, $hour);
        $queryOk = $db->real_query($sql);
        if (!$queryOk) {
            DebugMessage("SQL error: " . $db->errno . ' ' . $db->error . " - " . substr(preg_replace('/[\\r\\n]/', ' ', $sql), 0, 500), E_USER_WARNING);
        } else {
            $rowCount = $db->affected_rows;
            DebugMessage("{$rowCount} seller hourly rows updated for hour {$hour}");
        }
    }
}
예제 #4
0
function NextMailFile()
{
    $dir = scandir(substr(BOUNCEBACK_PATH, 0, -1), SCANDIR_SORT_ASCENDING);
    $lockFail = false;
    $gotFile = false;
    foreach ($dir as $fileName) {
        if (preg_match('/^(\\d+)\\./', $fileName, $res)) {
            if (($handle = fopen(BOUNCEBACK_PATH . $fileName, 'rb')) === false) {
                continue;
            }
            if (!flock($handle, LOCK_EX | LOCK_NB)) {
                $lockFail = true;
                fclose($handle);
                continue;
            }
            if (feof($handle)) {
                fclose($handle);
                unlink(BOUNCEBACK_PATH . $fileName);
                continue;
            }
            $ts = intval($res[1], 10);
            $gotFile = $fileName;
            break;
        }
    }
    unset($dir);
    if (!$gotFile) {
        if ($lockFail) {
            sleep(3);
            return true;
        }
        return false;
    }
    DebugMessage('Found message received at ' . date('Y-m-d H:i:s', $ts) . ', ' . TimeDiff($ts));
    $message = fread($handle, min(filesize(BOUNCEBACK_PATH . $fileName), 4194304));
    ftruncate($handle, 0);
    fclose($handle);
    unlink(BOUNCEBACK_PATH . $fileName);
    $mailId = false;
    if (preg_match('/X-Undermine-MailID:\\s*([a-zA-Z0-9_-]{27})/', $message, $res)) {
        $mailId = $res[1];
    } elseif (preg_match('/[Mm]essage ID: ([a-zA-Z0-9_-]{27})/', $message, $res)) {
        $mailId = $res[1];
    }
    if (!$mailId) {
        DebugMessage('Could not find message ID, forwarding to editor');
        NewsstandMail('*****@*****.**', 'The Editor', 'Unparsed notification reply', $message);
    } else {
        $address = GetAddressByMailID($mailId);
        if (!$address) {
            DebugMessage('Could not find address for mail ID ' . $mailId);
        } else {
            $cnt = DisableEmailAddress($address['address']);
            DebugMessage('Address ' . $address['address'] . ' removed from ' . $cnt . ' account' . ($cnt == 1 ? '' : 's') . '.');
        }
    }
    return true;
}
예제 #5
0
function FetchRegionData($region)
{
    global $caughtKill;
    $region = trim(strtolower($region));
    $results = [];
    DebugMessage("Fetching realms for {$region}");
    $url = GetBattleNetURL($region, 'wow/realm/status');
    $jsonString = HTTP::Get($url);
    $json = json_decode($jsonString, true);
    if (json_last_error() != JSON_ERROR_NONE) {
        DebugMessage("Error decoding " . strlen($jsonString) . " length JSON string for {$region}: " . json_last_error_msg(), E_USER_WARNING);
        return $results;
    }
    if (!isset($json['realms'])) {
        DebugMessage("Did not find realms in realm status JSON for {$region}", E_USER_WARNING);
        return $results;
    }
    $slugMap = [];
    foreach ($json['realms'] as $realmRow) {
        if ($caughtKill) {
            break;
        }
        if (!isset($realmRow['slug'])) {
            continue;
        }
        $slug = $realmRow['slug'];
        if (isset($results[$slug])) {
            $results[$slug]['name'] = $realmRow['name'];
            continue;
        }
        $resultRow = ['name' => $realmRow['name'], 'canonical' => 1];
        $results[$slug] = $resultRow;
        $slugMap[$slug] = [$slug];
        if (isset($realmRow['connected_realms'])) {
            foreach ($realmRow['connected_realms'] as $connectedSlug) {
                if ($connectedSlug == $slug) {
                    continue;
                }
                $results[$connectedSlug] = ['name' => ''];
                $slugMap[$slug][] = $connectedSlug;
            }
        }
    }
    $chunks = array_chunk($slugMap, REALM_CHUNK_SIZE, true);
    foreach ($chunks as $chunk) {
        DebugMessage("Fetching auction data for {$region} " . implode(', ', array_keys($chunk)));
        $urls = [];
        foreach (array_keys($chunk) as $slug) {
            $urls[$slug] = GetBattleNetURL($region, 'wow/auction/data/' . $slug);
        }
        $started = JSNow();
        $dataUrls = [];
        $jsons = FetchURLBatch($urls);
        foreach ($chunk as $slug => $slugs) {
            $json = [];
            if (!isset($jsons[$slug])) {
                DebugMessage("No HTTP response for {$region} {$slug}", E_USER_WARNING);
            } else {
                $json = json_decode($jsons[$slug], true);
                if (json_last_error() != JSON_ERROR_NONE) {
                    DebugMessage("Error decoding JSON string for {$region} {$slug}: " . json_last_error_msg(), E_USER_WARNING);
                    $json = [];
                }
            }
            $modified = isset($json['files'][0]['lastModified']) ? $json['files'][0]['lastModified'] : 0;
            $url = isset($json['files'][0]['url']) ? $json['files'][0]['url'] : '';
            if ($url) {
                $dataUrls[$slug] = $url;
            }
            foreach ($slugs as $connectedSlug) {
                $results[$connectedSlug]['checked'] = $started;
                $results[$connectedSlug]['modified'] = $modified;
            }
        }
        $dataHeads = FetchURLBatch($dataUrls, [CURLOPT_HEADER => true, CURLOPT_NOBODY => true]);
        foreach ($chunk as $slug => $slugs) {
            $fileDate = 0;
            if (isset($dataHeads[$slug])) {
                if (preg_match('/(?:^|\\n)Last-Modified: ([^\\n]+)/i', $dataHeads[$slug], $res)) {
                    $fileDate = strtotime($res[1]) * 1000;
                } elseif ($dataHeads[$slug]) {
                    DebugMessage("Found no last-modified header for {$region} {$slug} at " . $dataUrls[$slug] . "\n" . $dataHeads[$slug], E_USER_WARNING);
                }
            } elseif (isset($dataUrls[$slug])) {
                DebugMessage("Fetched no header for {$region} {$slug} at " . $dataUrls[$slug], E_USER_WARNING);
            }
            foreach ($slugs as $connectedSlug) {
                $results[$connectedSlug]['file'] = $fileDate;
            }
        }
    }
    ksort($results);
    return $results;
}
예제 #6
0
function GetRussianOwnerRealms($region)
{
    global $db, $caughtKill;
    $ruID = 0;
    $ruSlug = '';
    $ruToRun = array();
    $stmt = $db->prepare('select id, slug from tblRealm where region=? and locale=\'ru_RU\' and ownerrealm is null');
    $stmt->bind_param('s', $region);
    $stmt->execute();
    $stmt->bind_result($ruID, $ruSlug);
    while ($stmt->fetch()) {
        heartbeat();
        if ($caughtKill) {
            return;
        }
        DebugMessage("Getting ownerrealm for russian slug {$ruSlug}");
        $url = GetBattleNetURL($region, 'wow/realm/status?realms=' . $ruSlug . '&locale=ru_RU');
        $ruRealm = json_decode(FetchHTTP($url), true, 512, JSON_BIGINT_AS_STRING);
        if (json_last_error() != JSON_ERROR_NONE) {
            DebugMessage("{$url} did not return valid JSON");
            continue;
        }
        if (!isset($ruRealm['realms']) || count($ruRealm['realms']) == 0) {
            DebugMessage("{$url} returned no realms");
            continue;
        }
        $ruOwner = str_replace(' ', '', $ruRealm['realms'][0]['name']);
        $ruToRun[] = sprintf('update tblRealm set ownerrealm = \'%s\' where id = %d', $db->escape_string($ruOwner), $ruID);
    }
    $stmt->close();
    if ($caughtKill) {
        return;
    }
    foreach ($ruToRun as $sql) {
        heartbeat();
        if ($caughtKill) {
            return;
        }
        if (!$db->real_query($sql)) {
            DebugMessage(sprintf("%s: %s", $sql, $db->error), E_USER_WARNING);
        }
    }
}
예제 #7
0
    BnetGet();
    exit;
}
header('Content-type: text/html; charset=UTF-8');
echo <<<EOF
<html><head><title>Realm Status</title>
<style type="text/css">
td { border-top: 1px solid black }
td, th { padding: 4px }
td.r { text-align: right }

</style></head><body>
EOF;
echo '<h1>' . date('Y-m-d H:i:s') . '</h1>';
if (!DBConnect()) {
    DebugMessage('Cannot connect to db!', E_USER_ERROR);
}
ShowRealms();
ShowMemcacheStats();
ShowLogs();
ShowErrors();
echo '</body></html>';
function BnetGet()
{
    $parts = explode('-', $_GET['bnetget'], 2);
    if (count($parts) != 2) {
        echo 'Not enough parts.';
        exit;
    }
    switch ($parts[0]) {
        case 'US':
예제 #8
0
function CreateBitPayInvoice($loginState)
{
    $paid = GetIsPaid($loginState);
    if (!$paid['accept']) {
        DebugMessage("User " . $loginState['id'] . " attempted to create BitPay invoice when we would not accept payments.");
        return [];
    }
    $priceAmount = preg_match('/\\d+\\.\\d+/', SUBSCRIPTION_PAID_PRICE, $res) ? $res[0] : false;
    $priceCurrency = preg_match('/\\b[A-Z]{3}\\b/', SUBSCRIPTION_PAID_PRICE, $res) ? $res[0] : false;
    if (!$priceAmount || !$priceCurrency) {
        DebugMessage("Could not find price ({$priceAmount}) or currency ({$priceCurrency}) from " . SUBSCRIPTION_PAID_PRICE . " when creating BitPay invoice.");
        return [];
    }
    $LANG = GetLang($loginState['locale']);
    $toPost = ['price' => $priceAmount, 'currency' => $priceCurrency, 'posData' => $paid['accept']['custom'], 'fullNotifications' => true, 'notificationURL' => SUBSCRIPTION_BITPAY_IPN_URL, 'notificationEmail' => SUBSCRIPTION_ERRORS_EMAIL_ADDRESS, 'redirectURL' => 'https://' . strtolower($_SERVER["HTTP_HOST"]) . '/#subscription', 'itemDesc' => $LANG['paidSubscription'] . ' - ' . round(SUBSCRIPTION_PAID_ADDS_SECONDS / 86400) . ' ' . $LANG['timeDays']];
    $headers = ['Content-Type: application/json; charset=utf-8', 'Authorization: Basic ' . base64_encode(SUBSCRIPTION_BITPAY_KEY . ':')];
    $jsonString = \Newsstand\HTTP::Post(SUBSCRIPTION_BITPAY_INVOICE_URL, json_encode($toPost), $headers);
    if (!$jsonString) {
        DebugMessage("No response from BitPay having sent:\n" . json_encode($toPost) . "\n" . print_r($headers, true));
        return [];
    }
    $json = json_decode($jsonString, true);
    if (json_last_error() != JSON_ERROR_NONE) {
        DebugMessage("Invalid response from BitPay:\n{$jsonString}\nHaving sent:\n" . json_encode($toPost) . "\n" . print_r($headers, true));
        return [];
    }
    if (!UpdateBitPayTransaction($json, true)) {
        return [];
    }
    return ['url' => $json['url']];
}
예제 #9
0
function SendAndroidNotifications($regions)
{
    global $db;
    global $timeZones, $timeLeftCodes, $regionNames;
    $sent = [];
    $AndroidEndpoint = 'https://android.googleapis.com/gcm/send';
    foreach ($regions as $region) {
        $properRegion = strtoupper($region);
        if ($properRegion == 'US') {
            $properRegion = 'NA';
        }
        $sql = 'select * from tblWowToken w where region = ? order by `when` desc limit 2';
        $stmt = $db->prepare($sql);
        $stmt->bind_param('s', $region);
        $stmt->execute();
        $result = $stmt->get_result();
        $bothTokenData = DBMapArray($result, null);
        $tokenData = array_shift($bothTokenData);
        $prevTokenData = count($bothTokenData) ? array_shift($bothTokenData) : [];
        $stmt->close();
        if (!$prevTokenData) {
            continue;
        }
        if ($tokenData['marketgold'] == $prevTokenData['marketgold']) {
            continue;
        }
        if ($tokenData['result'] != 1 || $tokenData['result'] != $prevTokenData['result']) {
            continue;
        }
        $d = new DateTime('now', timezone_open($timeZones[$region]));
        $d->setTimestamp(strtotime($tokenData['when']));
        $formatted = ['BUY' => number_format($tokenData['marketgold']), 'TIMETOSELL' => isset($timeLeftCodes[$tokenData['timeleft']]) ? $timeLeftCodes[$tokenData['timeleft']] : $tokenData['timeleft'], 'UPDATED' => $d->format('M j g:ia T')];
        $direction = $tokenData['marketgold'] > $prevTokenData['marketgold'] ? 'over' : 'under';
        $sql = <<<EOF
select s.endpoint, s.id, e.region, e.value
from tblWowTokenSubs s
join tblWowTokenEvents e on e.subid = s.id
where s.lastfail is null
and e.direction = '{$direction}'
and e.region = '{$properRegion}'
and s.endpoint like '{$AndroidEndpoint}%'
EOF;
        if ($direction == 'over') {
            $sql .= ' and e.value >= ' . $prevTokenData['marketgold'] . ' and e.value < ' . $tokenData['marketgold'];
        } else {
            $sql .= ' and e.value <= ' . $prevTokenData['marketgold'] . ' and e.value > ' . $tokenData['marketgold'];
        }
        $stmt = $db->prepare($sql);
        $stmt->execute();
        $result = $stmt->get_result();
        $rows = DBMapArray($result, ['id']);
        $stmt->close();
        if (count($rows) == 0) {
            continue;
        }
        //sells in " . $formatted['TIMETOSELL'] . '
        $message = $regionNames[$properRegion] . ' price %s: now ' . $formatted['BUY'] . "g, as of " . $formatted['UPDATED'] . '.';
        $chunks = array_chunk($rows, 50, true);
        foreach ($chunks as $chunk) {
            $lookup = [];
            $toSend = [];
            $failed = [];
            $successful = [];
            foreach ($chunk as $id => $row) {
                $registrationId = substr($row['endpoint'], strlen($AndroidEndpoint) + 1);
                $msg = sprintf($message, $direction . ' ' . number_format($row['value'], 0) . 'g');
                $key = md5($row['endpoint']);
                if (!isset($sent[$key])) {
                    $lookup[] = $id;
                    $toSend[] = $registrationId;
                    $sent[$key] = $msg;
                } else {
                    $sent[$key] .= " \n" . $msg;
                }
                MCSet('tokennotify-' . $key, $sent[$key], 8 * 60 * 60);
            }
            if (!count($toSend)) {
                continue;
            }
            $toSend = json_encode(['registration_ids' => $toSend, 'time_to_live' => 4 * 60 * 60]);
            $headers = ['Authorization: key=' . ANDROID_GCM_KEY, 'Content-Type: application/json'];
            $outHeaders = [];
            $ret = \Newsstand\HTTP::Post($AndroidEndpoint, $toSend, $headers, $outHeaders);
            $ret = json_decode($ret, true);
            if (json_last_error() != JSON_ERROR_NONE || !isset($ret['results'])) {
                if (count($lookup) == 1 && isset($outHeaders['responseCode']) && $outHeaders['responseCode'] == '404') {
                    // only sent one, which failed, so mark it as failed
                    $successful = [];
                    $failed = $lookup;
                } else {
                    // can only assume all went through
                    DebugMessage("Bad response from {$AndroidEndpoint}\n" . print_r($headers, true) . $toSend . "\n" . print_r($outHeaders, true) . "\n{$ret}");
                    $successful = $lookup;
                    $failed = [];
                }
            } else {
                for ($x = 0; $x < count($ret['results']); $x++) {
                    if (isset($ret['results'][$x]['error'])) {
                        $failed[] = $lookup[$x];
                    } else {
                        $successful[] = $lookup[$x];
                    }
                }
            }
            $stmt = $db->prepare('update tblWowTokenEvents set lasttrigger=now() where subid in (' . implode(',', $lookup) . ') and region=\'' . $properRegion . '\' and direction=\'' . $direction . '\'');
            $stmt->execute();
            $stmt->close();
            if (count($successful)) {
                $stmt = $db->prepare('update tblWowTokenSubs set lastpush=now() where id in (' . implode(',', $successful) . ')');
                $stmt->execute();
                $stmt->close();
            }
            if (count($failed)) {
                $stmt = $db->prepare('update tblWowTokenSubs set lastpush=now(), lastfail=now() where id in (' . implode(',', $failed) . ')');
                $stmt->execute();
                $stmt->close();
            }
            DebugMessage('Sent ' . count($lookup) . ' messages to ' . $AndroidEndpoint . ' - ' . count($successful) . ' successful, ' . count($failed) . ' failed.');
        }
    }
}
예제 #10
0
파일: banip.php 프로젝트: erorus/newsstand
<?php

require_once __DIR__ . '/../incl/incl.php';
require_once __DIR__ . '/../incl/api.incl.php';
if (!isset($argv[1])) {
    DebugMessage("Enter IP to ban on command line.\n");
    exit(1);
}
$ip = trim($argv[1]);
if ($ip == false) {
    MCDelete(BANLIST_CACHEKEY);
    DebugMessage("Cleared banlist from memcache.\n");
    exit;
}
$ret = BanIP($ip);
if ($ret) {
    DebugMessage("{$ip} added to ban list.\n");
} else {
    if (IPIsBanned($ip)) {
        DebugMessage("{$ip} already on ban list.\n");
    } else {
        DebugMessage("{$ip} NOT added to ban list.\n");
    }
}
예제 #11
0
        $cjson = json_decode(\Newsstand\HTTP::Get($url), true);
        if (!isset($cjson['appearance'])) {
            continue;
        }
        $imgUrl = "http://render-{$region}.worldofwarcraft.com/character/" . preg_replace('/-avatar\\.jpg$/', '-inset.jpg', $cjson['thumbnail']);
        DebugMessage("Fetching {$imgUrl}");
        $img = \Newsstand\HTTP::Get($imgUrl);
        if ($img) {
            $hits++;
            $id = MakeID();
            $helm = $cjson['appearance']['showHelm'] ? 1 : 0;
            DebugMessage("Saving {$id} as {$c['race']} {$c['gender']} {$helm}");
            file_put_contents(CAPTCHA_DIR . '/' . $id . '.jpg', $img);
            $sql = 'INSERT INTO tblCaptcha (id, race, gender, helm) VALUES (?, ?, ?, ?)';
            $stmt = $db->prepare($sql);
            $stmt->bind_param('iiii', $id, $c['race'], $c['gender'], $helm);
            $stmt->execute();
            $stmt->close();
        }
    }
}
DebugMessage('Done!');
function MakeID()
{
    static $lastTime = 0, $lastIncrement = 0;
    if ($lastTime != time()) {
        $lastTime = time();
        $lastIncrement = 0;
    }
    return ($lastTime << 8) + $lastIncrement++ & 0xffffffff;
}
예제 #12
0
function FetchSnapshot()
{
    global $db, $region;
    $lockName = "fetchsnapshot_{$region}";
    $stmt = $db->prepare('select get_lock(?, 30)');
    $stmt->bind_param('s', $lockName);
    $stmt->execute();
    $lockSuccess = null;
    $stmt->bind_result($lockSuccess);
    if (!$stmt->fetch()) {
        $lockSuccess = null;
    }
    $stmt->close();
    if ($lockSuccess != '1') {
        DebugMessage("Could not get mysql lock for {$lockName}.");
        return 30;
    }
    $earlyCheckSeconds = EARLY_CHECK_SECONDS;
    $nextRealmSql = <<<ENDSQL
    select r.house, min(r.canonical), count(*) c, ifnull(hc.nextcheck, s.nextcheck) upd, s.lastupdate, s.mindelta, hc.lastchecksuccessresult
    from tblRealm r
    left join (
        select deltas.house, timestampadd(second, least(ifnull(min(delta)-{$earlyCheckSeconds}, 45*60), 150*60), max(deltas.updated)) nextcheck, max(deltas.updated) lastupdate, min(delta) mindelta
        from (
            select sn.updated,
            if(@prevhouse = sn.house and sn.updated > timestampadd(hour, -72, now()), unix_timestamp(sn.updated) - @prevdate, null) delta,
            @prevdate := unix_timestamp(sn.updated) updated_ts,
            @prevhouse := sn.house house
            from (select @prevhouse := null, @prevdate := null) setup, tblSnapshot sn
            order by sn.house, sn.updated) deltas
        group by deltas.house
        ) s on s.house = r.house
    left join tblHouseCheck hc on hc.house = r.house
    where r.region = ?
    and r.house is not null
    and r.canonical is not null
    group by r.house
    order by ifnull(upd, '2000-01-01') asc, c desc, r.house asc
    limit 1
ENDSQL;
    $house = $slug = $realmCount = $nextDate = $lastDate = $minDelta = $lastSuccessJson = null;
    $stmt = $db->prepare($nextRealmSql);
    $stmt->bind_param('s', $region);
    $stmt->execute();
    $stmt->bind_result($house, $slug, $realmCount, $nextDate, $lastDate, $minDelta, $lastSuccessJson);
    $gotRealm = $stmt->fetch() === true;
    $stmt->close();
    if (!$gotRealm) {
        DebugMessage("No {$region} realms to fetch!");
        ReleaseDBLock($lockName);
        return 30;
    }
    if (strtotime($nextDate) > time() && strtotime($nextDate) < time() + 3.5 * 60 * 60) {
        $delay = strtotime($nextDate) - time();
        DebugMessage("No {$region} realms ready yet, waiting " . SecondsOrMinutes($delay) . ".");
        ReleaseDBLock($lockName);
        return $delay;
    }
    SetHouseNextCheck($house, time() + 600, null);
    ReleaseDBLock($lockName);
    DebugMessage("{$region} {$slug} fetch for house {$house} to update {$realmCount} realms, due since " . (is_null($nextDate) ? 'unknown' : SecondsOrMinutes(time() - strtotime($nextDate)) . ' ago'));
    $url = GetBattleNetURL($region, "wow/auction/data/{$slug}");
    $outHeaders = [];
    $dta = [];
    $json = \Newsstand\HTTP::Get($url, [], $outHeaders);
    if ($json === false && isset($outHeaders['body'])) {
        // happens if server returns non-200 code, but we'll want that json anyway
        $json = $outHeaders['body'];
    }
    if ($json !== false) {
        $dta = json_decode($json, true);
        if (json_last_error() != JSON_ERROR_NONE) {
            $dta = [];
        }
    }
    if (!isset($dta['files']) && !is_null($lastSuccessJson)) {
        // no files in current status json, probably "internal server error"
        // check the headers on our last known good data url
        $lastGoodDta = json_decode($lastSuccessJson, true);
        if (json_last_error() != JSON_ERROR_NONE) {
            DebugMessage("{$region} {$slug} invalid JSON for last successful json\n" . $lastSuccessJson, E_USER_WARNING);
        } elseif (!isset($lastGoodDta['files'])) {
            DebugMessage("{$region} {$slug} no files in the last success json?!", E_USER_WARNING);
        } else {
            usort($lastGoodDta['files'], 'AuctionFileSort');
            $fileInfo = end($lastGoodDta['files']);
            $oldModified = ceil(intval($fileInfo['lastModified'], 10) / 1000);
            DebugMessage("{$region} {$slug} returned no files. Checking headers on URL from " . date('Y-m-d H:i:s', $oldModified));
            $headers = \Newsstand\HTTP::Head(preg_replace('/^http:/', 'https:', $fileInfo['url']));
            if (isset($headers['Last-Modified'])) {
                $newModified = strtotime($headers['Last-Modified']);
                $fileInfo['lastModified'] = $newModified * 1000;
                $dta['files'] = [$fileInfo];
                if (abs($oldModified - $newModified) < 10) {
                    DebugMessage("{$region} {$slug} data file has unchanged last modified date from last successful parse.");
                } else {
                    DebugMessage("{$region} {$slug} data file modified " . date('Y-m-d H:i:s', $newModified) . ".");
                }
            } else {
                DebugMessage("{$region} {$slug} data file failed fetching last modified date via HEAD method.");
            }
        }
    }
    if (!isset($dta['files'])) {
        $delay = GetCheckDelay(strtotime($lastDate));
        DebugMessage("{$region} {$slug} returned no files. Waiting " . SecondsOrMinutes($delay) . ".", E_USER_WARNING);
        SetHouseNextCheck($house, time() + $delay, $json);
        \Newsstand\HTTP::AbandonConnections();
        return 0;
    }
    usort($dta['files'], 'AuctionFileSort');
    $fileInfo = end($dta['files']);
    $modified = ceil(intval($fileInfo['lastModified'], 10) / 1000);
    $lastDateUnix = is_null($lastDate) ? $modified - 1 : strtotime($lastDate);
    $delay = 0;
    if (!is_null($minDelta) && $modified <= $lastDateUnix) {
        if ($lastDateUnix + $minDelta > time()) {
            // we checked for an earlier-than-expected snapshot, didn't see one
            $delay = $lastDateUnix + $minDelta - time() + 8;
            // next check will be 8 seconds after expected update
        } else {
            if ($lastDateUnix + $minDelta + 45 > time()) {
                // this is the first check after we expected a new snapshot, but didn't see one.
                // don't trust api, assume data file URL won't change, and check last-modified time on data file
                $headers = \Newsstand\HTTP::Head(preg_replace('/^http:/', 'https:', $fileInfo['url']));
                if (isset($headers['Last-Modified'])) {
                    $newModified = strtotime($headers['Last-Modified']);
                    if ($newModified > $modified) {
                        DebugMessage("{$region} {$slug} data file indicates last modified {$newModified} " . date('H:i:s', $newModified) . ", ignoring API result.");
                        $modified = $newModified;
                    } else {
                        if ($newModified == $modified) {
                            DebugMessage("{$region} {$slug} data file has last modified date matching API result.");
                        } else {
                            DebugMessage("{$region} {$slug} data file has last modified date earlier than API result: {$newModified} " . date('H:i:s', $newModified) . ".");
                        }
                    }
                } else {
                    DebugMessage("{$region} {$slug} data file failed fetching last modified date via HEAD method.");
                }
            }
        }
    }
    if ($modified <= $lastDateUnix) {
        if ($delay <= 0) {
            $delay = GetCheckDelay($modified);
        }
        DebugMessage("{$region} {$slug} still not updated since {$modified} " . date('H:i:s', $modified) . " (" . SecondsOrMinutes(time() - $modified) . " ago). Waiting " . SecondsOrMinutes($delay) . ".");
        SetHouseNextCheck($house, time() + $delay, $json);
        return 0;
    }
    DebugMessage("{$region} {$slug} updated {$modified} " . date('H:i:s', $modified) . " (" . SecondsOrMinutes(time() - $modified) . " ago), fetching auction data file");
    $dlStart = microtime(true);
    $data = \Newsstand\HTTP::Get(preg_replace('/^http:/', 'https:', $fileInfo['url']), [], $outHeaders);
    $dlDuration = microtime(true) - $dlStart;
    if (!$data || substr($data, -4) != "]\r\n}") {
        if (!$data) {
            DebugMessage("{$region} {$slug} data file empty. Waiting 5 seconds and trying again.");
            sleep(5);
        } else {
            DebugMessage("{$region} {$slug} data file malformed. Waiting 10 seconds and trying again.");
            sleep(10);
        }
        $dlStart = microtime(true);
        $data = \Newsstand\HTTP::Get($fileInfo['url'] . (parse_url($fileInfo['url'], PHP_URL_QUERY) ? '&' : '?') . 'please', [], $outHeaders);
        $dlDuration = microtime(true) - $dlStart;
    }
    if (!$data) {
        DebugMessage("{$region} {$slug} data file empty. Will try again in 30 seconds.");
        SetHouseNextCheck($house, time() + 30, $json);
        \Newsstand\HTTP::AbandonConnections();
        return 10;
    }
    if (substr($data, -4) != "]\r\n}") {
        $delay = GetCheckDelay($modified);
        DebugMessage("{$region} {$slug} data file still probably malformed. Waiting " . SecondsOrMinutes($delay) . ".");
        SetHouseNextCheck($house, time() + $delay, $json);
        return 0;
    }
    $xferBytes = isset($outHeaders['X-Original-Content-Length']) ? $outHeaders['X-Original-Content-Length'] : strlen($data);
    DebugMessage("{$region} {$slug} data file " . strlen($data) . " bytes" . ($xferBytes != strlen($data) ? ' (transfer length ' . $xferBytes . ', ' . round($xferBytes / strlen($data) * 100, 1) . '%)' : '') . ", " . round($dlDuration, 2) . "sec, " . round($xferBytes / 1000 / $dlDuration) . "KBps");
    if ($xferBytes >= strlen($data) && strlen($data) > 65536) {
        DebugMessage('No compression? ' . print_r($outHeaders, true));
    }
    if ($xferBytes / 1000 / $dlDuration < 200 && in_array($region, ['US', 'EU'])) {
        DebugMessage("Speed under 200KBps, closing persistent connections");
        \Newsstand\HTTP::AbandonConnections();
    }
    $successJson = json_encode($dta);
    // will include any updates from using lastSuccessJson
    $stmt = $db->prepare('INSERT INTO tblHouseCheck (house, nextcheck, lastcheck, lastcheckresult, lastchecksuccess, lastchecksuccessresult) VALUES (?, NULL, now(), ?, now(), ?) ON DUPLICATE KEY UPDATE nextcheck=values(nextcheck), lastcheck=values(lastcheck), lastcheckresult=values(lastcheckresult), lastchecksuccess=values(lastchecksuccess), lastchecksuccessresult=values(lastchecksuccessresult)');
    $stmt->bind_param('iss', $house, $json, $successJson);
    $stmt->execute();
    $stmt->close();
    $stmt = $db->prepare('INSERT INTO tblSnapshot (house, updated) VALUES (?, from_unixtime(?))');
    $stmt->bind_param('ii', $house, $modified);
    $stmt->execute();
    $stmt->close();
    MCSet('housecheck_' . $house, time(), 0);
    $fileName = "{$modified}-" . str_pad($house, 5, '0', STR_PAD_LEFT) . ".json";
    file_put_contents(SNAPSHOT_PATH . $fileName, $data, LOCK_EX);
    link(SNAPSHOT_PATH . $fileName, SNAPSHOT_PATH . 'parse/' . $fileName);
    if (in_array($region, ['US', 'EU'])) {
        link(SNAPSHOT_PATH . $fileName, SNAPSHOT_PATH . 'watch/' . $fileName);
    }
    unlink(SNAPSHOT_PATH . $fileName);
    return 0;
}
예제 #13
0
<?php

require_once __DIR__ . '/../incl/incl.php';
require_once __DIR__ . '/../incl/api.incl.php';
if (!isset($argv[1])) {
    DebugMessage("Enter IP to unban on command line.\n");
    exit(1);
}
$ip = trim($argv[1]);
if (!IPIsBanned($ip)) {
    DebugMessage("{$ip} was not banned.\n");
    exit(1);
}
if (file_exists(BANLIST_FILENAME)) {
    $lines = shell_exec('grep ' . escapeshellarg("^{$ip} ") . ' ' . escapeshellarg(BANLIST_FILENAME));
    if (!$lines) {
        DebugMessage('Found no lines in ' . BANLIST_FILENAME . "for {$ip}\n");
    } else {
        $other = shell_exec('grep -v ' . escapeshellarg("^{$ip} ") . ' ' . escapeshellarg(BANLIST_FILENAME));
        file_put_contents(BANLIST_FILENAME, $other, LOCK_EX);
    }
} else {
    DebugMessage("Could not find " . BANLIST_FILENAME . "\n");
    exit(1);
}
MCDelete(BANLIST_CACHEKEY);
MCDelete(BANLIST_CACHEKEY . '_' . $ip);
DebugMessage("{$ip} is unbanned.\n");
예제 #14
0
function MCHouseLock($house, $waitSeconds = 30)
{
    global $MCHousesLocked;
    static $registeredShutdown = false;
    if (isset($MCHousesLocked[$house])) {
        return true;
    }
    $giveUpAt = microtime(true) + $waitSeconds;
    $me = ['pid' => getmypid(), 'script' => $_SERVER["SCRIPT_FILENAME"], 'when' => time()];
    do {
        if (MCAdd('mchouselock_' . $house, $me, 30 * 60)) {
            $MCHousesLocked[$house] = true;
            if (!$registeredShutdown) {
                $registeredShutdown = true;
                register_shutdown_function('MCHouseUnlock');
            }
            return true;
        }
        usleep(500000);
    } while ($giveUpAt > microtime(true));
    $currentLock = MCGet('mchouselock_' . $house);
    DebugMessage("Could not get house lock for {$house}, owned by " . $currentLock['pid'] . ' ' . $currentLock['script'] . ' ' . TimeDiff($currentLock['when']));
    return false;
}
예제 #15
0
function UpdateGlobalDataJson()
{
    global $caughtKill, $db;
    if ($caughtKill) {
        return;
    }
    heartbeat();
    DebugMessage("Updating global data json");
    $stmt = $db->prepare('SELECT item, floor(avg(median)) median FROM tblItemGlobal where bonusset=0 group by item');
    $stmt->execute();
    $result = $stmt->get_result();
    $prices = DBMapArray($result, null);
    $stmt->close();
    $json = [];
    foreach ($prices as $priceRow) {
        $json[$priceRow['item']] = $priceRow['median'];
    }
    file_put_contents(__DIR__ . '/../public/globalprices.json', json_encode($json, JSON_NUMERIC_CHECK | JSON_FORCE_OBJECT), LOCK_EX);
}
예제 #16
0
function AddDailyData()
{
    global $db, $caughtKill;
    if ($caughtKill) {
        return;
    }
    $sql = <<<'EOF'
select distinct hc.house, date(sn.updated) dt
from tblHouseCheck hc
join tblSnapshot sn on sn.house = hc.house
where ifnull(hc.lastdaily, '2000-01-01') < date(timestampadd(day, -1, now()))
and sn.updated > timestampadd(day, 1, ifnull(hc.lastdaily, '2000-01-01'))
and sn.updated < date(now())
and sn.flags & 1 = 0
order by 1, 2
EOF;
    $stmt = $db->prepare($sql);
    $stmt->execute();
    $result = $stmt->get_result();
    $houses = $result->fetch_all(MYSQLI_ASSOC);
    $stmt->close();
    DebugMessage(count($houses) . " houses need updates");
    $sqlPattern = <<<'EOF'
replace into tblItemHistoryDaily
(SELECT `ihh`.item, `ihh`.house, `ihh`.`when`,
nullif(least(
ifnull(silver00, 4294967295),ifnull(silver01, 4294967295),ifnull(silver02, 4294967295),ifnull(silver03, 4294967295),
ifnull(silver04, 4294967295),ifnull(silver05, 4294967295),ifnull(silver06, 4294967295),ifnull(silver07, 4294967295),
ifnull(silver08, 4294967295),ifnull(silver09, 4294967295),ifnull(silver10, 4294967295),ifnull(silver11, 4294967295),
ifnull(silver12, 4294967295),ifnull(silver13, 4294967295),ifnull(silver14, 4294967295),ifnull(silver15, 4294967295),
ifnull(silver16, 4294967295),ifnull(silver17, 4294967295),ifnull(silver18, 4294967295),ifnull(silver19, 4294967295),
ifnull(silver20, 4294967295),ifnull(silver21, 4294967295),ifnull(silver22, 4294967295),ifnull(silver23, 4294967295)),4294967295) pricemin,

round((
ifnull(silver00, 0)+ifnull(silver01, 0)+ifnull(silver02, 0)+ifnull(silver03, 0)+
ifnull(silver04, 0)+ifnull(silver05, 0)+ifnull(silver06, 0)+ifnull(silver07, 0)+
ifnull(silver08, 0)+ifnull(silver09, 0)+ifnull(silver10, 0)+ifnull(silver11, 0)+
ifnull(silver12, 0)+ifnull(silver13, 0)+ifnull(silver14, 0)+ifnull(silver15, 0)+
ifnull(silver16, 0)+ifnull(silver17, 0)+ifnull(silver18, 0)+ifnull(silver19, 0)+
ifnull(silver20, 0)+ifnull(silver21, 0)+ifnull(silver22, 0)+ifnull(silver23, 0)
) / (24 -
isnull(silver00)-isnull(silver01)-isnull(silver02)-isnull(silver03)-
isnull(silver04)-isnull(silver05)-isnull(silver06)-isnull(silver07)-
isnull(silver08)-isnull(silver09)-isnull(silver10)-isnull(silver11)-
isnull(silver12)-isnull(silver13)-isnull(silver14)-isnull(silver15)-
isnull(silver16)-isnull(silver17)-isnull(silver18)-isnull(silver19)-
isnull(silver20)-isnull(silver21)-isnull(silver22)-isnull(silver23))) priceavg,

nullif(greatest(
ifnull(silver00, 0),ifnull(silver01, 0),ifnull(silver02, 0),ifnull(silver03, 0),
ifnull(silver04, 0),ifnull(silver05, 0),ifnull(silver06, 0),ifnull(silver07, 0),
ifnull(silver08, 0),ifnull(silver09, 0),ifnull(silver10, 0),ifnull(silver11, 0),
ifnull(silver12, 0),ifnull(silver13, 0),ifnull(silver14, 0),ifnull(silver15, 0),
ifnull(silver16, 0),ifnull(silver17, 0),ifnull(silver18, 0),ifnull(silver19, 0),
ifnull(silver20, 0),ifnull(silver21, 0),ifnull(silver22, 0),ifnull(silver23, 0)),0) pricemax,

coalesce(
silver00, silver01, silver02, silver03, silver04, silver05,
silver06, silver07, silver08, silver09, silver10, silver11,
silver12, silver13, silver14, silver15, silver16, silver17,
silver18, silver19, silver20, silver21, silver22, silver23) pricestart,

coalesce(
silver23, silver22, silver21, silver20, silver19, silver18,
silver17, silver16, silver15, silver14, silver13, silver12,
silver11, silver10, silver09, silver08, silver07, silver06,
silver05, silver04, silver03, silver02, silver01, silver00) priceend,

nullif(least(
ifnull(quantity00, 4294967295),ifnull(quantity01, 4294967295),ifnull(quantity02, 4294967295),ifnull(quantity03, 4294967295),
ifnull(quantity04, 4294967295),ifnull(quantity05, 4294967295),ifnull(quantity06, 4294967295),ifnull(quantity07, 4294967295),
ifnull(quantity08, 4294967295),ifnull(quantity09, 4294967295),ifnull(quantity10, 4294967295),ifnull(quantity11, 4294967295),
ifnull(quantity12, 4294967295),ifnull(quantity13, 4294967295),ifnull(quantity14, 4294967295),ifnull(quantity15, 4294967295),
ifnull(quantity16, 4294967295),ifnull(quantity17, 4294967295),ifnull(quantity18, 4294967295),ifnull(quantity19, 4294967295),
ifnull(quantity20, 4294967295),ifnull(quantity21, 4294967295),ifnull(quantity22, 4294967295),ifnull(quantity23, 4294967295)),4294967295) quantitymin,

round((
ifnull(quantity00, 0)+ifnull(quantity01, 0)+ifnull(quantity02, 0)+ifnull(quantity03, 0)+
ifnull(quantity04, 0)+ifnull(quantity05, 0)+ifnull(quantity06, 0)+ifnull(quantity07, 0)+
ifnull(quantity08, 0)+ifnull(quantity09, 0)+ifnull(quantity10, 0)+ifnull(quantity11, 0)+
ifnull(quantity12, 0)+ifnull(quantity13, 0)+ifnull(quantity14, 0)+ifnull(quantity15, 0)+
ifnull(quantity16, 0)+ifnull(quantity17, 0)+ifnull(quantity18, 0)+ifnull(quantity19, 0)+
ifnull(quantity20, 0)+ifnull(quantity21, 0)+ifnull(quantity22, 0)+ifnull(quantity23, 0)
) / (24 -
isnull(quantity00)-isnull(quantity01)-isnull(quantity02)-isnull(quantity03)-
isnull(quantity04)-isnull(quantity05)-isnull(quantity06)-isnull(quantity07)-
isnull(quantity08)-isnull(quantity09)-isnull(quantity10)-isnull(quantity11)-
isnull(quantity12)-isnull(quantity13)-isnull(quantity14)-isnull(quantity15)-
isnull(quantity16)-isnull(quantity17)-isnull(quantity18)-isnull(quantity19)-
isnull(quantity20)-isnull(quantity21)-isnull(quantity22)-isnull(quantity23))) quantityavg,

nullif(greatest(
ifnull(quantity00, 0),ifnull(quantity01, 0),ifnull(quantity02, 0),ifnull(quantity03, 0),
ifnull(quantity04, 0),ifnull(quantity05, 0),ifnull(quantity06, 0),ifnull(quantity07, 0),
ifnull(quantity08, 0),ifnull(quantity09, 0),ifnull(quantity10, 0),ifnull(quantity11, 0),
ifnull(quantity12, 0),ifnull(quantity13, 0),ifnull(quantity14, 0),ifnull(quantity15, 0),
ifnull(quantity16, 0),ifnull(quantity17, 0),ifnull(quantity18, 0),ifnull(quantity19, 0),
ifnull(quantity20, 0),ifnull(quantity21, 0),ifnull(quantity22, 0),ifnull(quantity23, 0)),0) quantitymax

FROM `tblItemHistoryHourly` ihh
JOIN `tblDBCItem` `i` ON `i`.`id` = `ihh`.`item`
WHERE i.stacksize > 1 and ihh.house = ? and ihh.`when` = ?)
EOF;
    foreach ($houses as $houseRow) {
        heartbeat();
        if ($caughtKill) {
            return;
        }
        if (!MCHouseLock($houseRow['house'])) {
            continue;
        }
        $stmt = $db->prepare($sqlPattern);
        $stmt->bind_param('is', $houseRow['house'], $houseRow['dt']);
        $queryOk = $stmt->execute();
        $rowCount = $db->affected_rows;
        $stmt->close();
        if (!$queryOk) {
            DebugMessage("SQL error: " . $db->errno . ' ' . $db->error . " - " . substr(preg_replace('/[\\r\\n]/', ' ', $sqlPattern), 0, 500), E_USER_WARNING);
            $rowCount = -1;
        } else {
            DebugMessage("{$rowCount} item daily rows updated for house {$houseRow['house']} for date {$houseRow['dt']}");
        }
        if ($rowCount >= 0) {
            $stmt = $db->prepare('INSERT INTO tblHouseCheck (house, lastdaily) VALUES (?, ?) ON DUPLICATE KEY UPDATE lastdaily = values(lastdaily)');
            $stmt->bind_param('is', $houseRow['house'], $houseRow['dt']);
            $stmt->execute();
            $stmt->close();
        }
        MCHouseUnlock($houseRow['house']);
    }
}
예제 #17
0
function GetGuild(&$characterNames, $guild, $realmName)
{
    global $db, $caughtKill, $allRealms;
    heartbeat();
    if ($caughtKill) {
        return;
    }
    if (!isset($allRealms[$realmName])) {
        DebugMessage('Could not find realm ' . $realmName);
        return;
    }
    $guildId = 0;
    $scanned = 0;
    $stmt = $db->prepare('select id, ifnull(scanned,\'2000-01-01\') from tblGuild where realm = ? and name = ?');
    $stmt->bind_param('is', $allRealms[$realmName]['id'], $guild);
    $stmt->execute();
    $stmt->bind_result($guildId, $scanned);
    $hasRow = $stmt->fetch() === true;
    $stmt->close();
    if ($hasRow) {
        if (strtotime($scanned) >= time() - 14 * 24 * 60 * 60) {
            return;
        }
    } else {
        $stmt = $db->prepare('insert into tblGuild (realm, name) values (?, ?)');
        $stmt->bind_param('is', $allRealms[$realmName]['id'], $guild);
        $stmt->execute();
        $stmt->close();
        $guildId = $db->insert_id;
    }
    DebugMessage("Getting guild <{$guild}> on {$realmName}");
    $url = GetBattleNetURL($allRealms[$realmName]['region'], "wow/guild/" . $allRealms[$realmName]['slug'] . "/" . rawurlencode($guild) . "?fields=members");
    $json = FetchHTTP($url);
    if (!$json) {
        return;
    }
    heartbeat();
    if ($caughtKill) {
        return;
    }
    $dta = json_decode($json, true);
    if (json_last_error() != JSON_ERROR_NONE) {
        return;
    }
    if (!isset($dta['members'])) {
        return;
    }
    $charCount = 0;
    $side = $dta['side'] + 1;
    foreach ($dta['members'] as $member) {
        if (!isset($member['character'])) {
            continue;
        }
        if (!isset($member['character']['name'])) {
            continue;
        }
        if (!isset($member['character']['realm'])) {
            continue;
        }
        if (!isset($allRealms[$member['character']['realm']])) {
            continue;
        }
        $charCount++;
        $member['character']['gender']++;
        // line up with db enum
        $stmt = $db->prepare('insert into tblCharacter (name, realm, scanned, race, class, gender, level) values (?, ?, NOW(), ?, ?, ?, ?) on duplicate key update lastmodified=null, scanned=values(scanned), race=values(race), class=values(class), gender=values(gender), level=values(level)');
        $stmt->bind_param('siiiii', $member['character']['name'], $allRealms[$member['character']['realm']]['id'], $member['character']['race'], $member['character']['class'], $member['character']['gender'], $member['character']['level']);
        $stmt->execute();
        $stmt->close();
        unset($characterNames[$allRealms[$member['character']['realm']]['ownerrealm']][$member['character']['name']]);
    }
    $stmt = $db->prepare('update tblGuild set scanned=now(), side=?, members=? where id = ?');
    $stmt->bind_param('iii', $side, $charCount, $guildId);
    $stmt->execute();
    $stmt->close();
}
예제 #18
0
function CategoryDealsItemList($house, $dealsSql, $flags = 0)
{
    global $canCache;
    $cacheKey = 'category_di4_' . md5($dealsSql) . '_' . $flags;
    if ($canCache && ($iidList = MCGetHouse($house, $cacheKey)) !== false) {
        return CategoryDealsItemListCached($house, $iidList, $flags);
    }
    $db = DBConnect();
    $region = GetRegion($house);
    $fullSql = <<<EOF
select aa.item, aa.bonusset,
    (select a.id
    from tblAuction a
    left join tblAuctionExtra ae on ae.house=a.house and ae.id = a.id
    join tblDBCItem i on a.item = i.id
    where a.buy > 0 and a.house=? and a.item=aa.item and ifnull(ae.bonusset,0) = aa.bonusset
    order by (a.buy/pow(1.15,(cast(ifnull(ae.level, i.level) as signed) - cast(i.level as signed))/15))/a.quantity limit 1) cheapestid
from (
    select ac.item, ac.bonusset, ac.c_total, ac.c_over, ac.price, gs.median
    from (
        select ab.item, ab.bonusset, count(*) c_total, sum(if(tis2.price > ab.price,1,0)) c_over, ab.price
        from (
            select tis.item, tis.bonusset, tis.price
            from tblItemSummary tis
            join tblDBCItem i on tis.item=i.id
            where tis.house = ?
            and tis.quantity > 0
            and 0 = (select count(*) from tblDBCItemVendorCost ivc where ivc.item=i.id)
            and i.class not in (16)
            and {$dealsSql}
EOF;
    if (($flags & CATEGORY_FLAGS_ALLOW_CRAFTED) == 0) {
        $fullSql .= ' and not exists (select 1 from tblDBCSpell s where s.crafteditem=i.id) ';
    }
    if ($flags & CATEGORY_FLAGS_DENY_NONCRAFTED) {
        $fullSql .= ' and exists (select 1 from tblDBCSpell s where s.crafteditem=i.id) ';
    }
    $fullSql .= <<<EOF
        ) ab
        join tblItemSummary tis2 on tis2.item = ab.item and tis2.bonusset = ab.bonusset
        join tblRealm r on r.house = tis2.house and r.canonical is not null
        where r.region = ?
        group by ab.item, ab.bonusset
    ) ac
    join tblItemGlobal gs on gs.item = ac.item and gs.bonusset = ac.bonusset and gs.region = ?
    where ((c_over/c_total) > 2/3 or c_total < 15)
) aa
where median > 1500000
and median > price
order by (cast(median as signed) - cast(price as signed))/greatest(5000000,price) * (c_over/c_total) desc
limit 15
EOF;
    $stmt = $db->stmt_init();
    if (!$stmt->prepare($fullSql)) {
        DebugMessage("Bad SQL: \n" . $fullSql, E_USER_ERROR);
    }
    $stmt->bind_param('iiss', $house, $house, $region, $region);
    $stmt->execute();
    $result = $stmt->get_result();
    if ($result === false && ($errMsg = $db->error)) {
        DebugMessage("No result: {$errMsg}\n" . $fullSql, E_USER_ERROR);
    }
    $iidList = DBMapArray($result, null);
    $stmt->close();
    MCSetHouse($house, $cacheKey, $iidList);
    return CategoryDealsItemListCached($house, $iidList, $flags);
}
예제 #19
0
function TransmogGenericItemList($house, $params)
{
    global $db, $canCache;
    $key = 'transmog_gi2_' . md5(json_encode($params));
    if ($canCache && ($tr = MCGetHouse($house, $key)) !== false) {
        return $tr;
    }
    DBConnect();
    if (is_array($params)) {
        $joins = isset($params['joins']) ? $params['joins'] : '';
        $where = isset($params['where']) ? ' and ' . $params['where'] : '';
        $group = isset($params['group']) ? array_merge($params['group'], [false]) : null;
    } else {
        $joins = '';
        $group = null;
        $where = $params == '' ? '' : ' and ' . $params;
    }
    $sql = <<<EOF
select ab.id, ab.display, ab.buy, ab.class, ab.subclass, ifnull(ab.type, -1 & ab.subclass) `type`, ab.subclassname
from (
    select aa.*, if(@previd = aa.display, 0, @previd := aa.display) previd
    from (select @previd := 0) aasetup, (
        SELECT i.id, i.display, a.buy, i.class, i.subclass, i.type, concat_ws('-', i.class, i.subclass) subclassname
        FROM `tblDBCItem` i
        join tblAuction a on a.item=i.id
        {$joins}
        WHERE i.auctionable=1
        and i.quality > 1
        {$where}
        and i.display is not null
        and i.flags & 2 = 0
        and a.house = ?
        and a.buy > 0
        order by i.display, a.buy) aa
    ) ab
where ab.previd > 0
EOF;
    $stmt = $db->prepare($sql);
    if (!$stmt) {
        DebugMessage("Bad SQL: \n" . $sql, E_USER_ERROR);
    }
    $stmt->bind_param('i', $house);
    $stmt->execute();
    $result = $stmt->get_result();
    $tr = DBMapArray($result, $group);
    $stmt->close();
    MCSetHouse($house, $key, $tr);
    return $tr;
}
예제 #20
0
<?php

require_once __DIR__ . '/../incl/incl.php';
require_once __DIR__ . '/../incl/memcache.incl.php';
if (!isset($argv[1])) {
    DebugMessage('Manual API Maintenance called without time argument. Add expected completion timestamp to command line (or 0 to end maintenance)', E_USER_ERROR);
}
APIMaintenance($argv[1], isset($argv[2]) ? $argv[2] : false);
예제 #21
0
<?php

chdir(__DIR__);
require_once '../incl/incl.php';
require_once '../incl/api.incl.php';
$logFileName = isset($argv[1]) ? $argv[1] : '../logs/access.log';
if (!file_exists($logFileName)) {
    DebugMessage("Can't find log file: {$logFileName}\n");
    exit(1);
}
$ipHits = [];
$fh = fopen($logFileName, 'r');
if ($fh) {
    while (($line = fgets($fh, 4096)) !== false) {
        if (strpos($line, '"GET /api/') !== false) {
            //} && (strpos($line, '(X11; Ubuntu; Linux i686; rv:25.0') !== false)) {
            preg_match('/^\\S+/', $line, $res);
            if (!isset($ipHits[$res[0]])) {
                $ipHits[$res[0]] = 0;
            }
            $ipHits[$res[0]]++;
        }
    }
}
fclose($fh);
arsort($ipHits, SORT_NUMERIC);
$x = 0;
foreach ($ipHits as $ip => $hits) {
    if (!IPIsBanned($ip)) {
        echo "{$ip} - {$hits}\n";
        if (++$x > 30) {
예제 #22
0
function CleanOldData()
{
    global $db, $caughtKill;
    if ($caughtKill) {
        return;
    }
    DebugMessage("Starting, getting houses");
    $house = null;
    $houses = [];
    $stmt = $db->prepare('SELECT DISTINCT house FROM tblRealm WHERE house is not null');
    $stmt->execute();
    $stmt->bind_result($house);
    while ($stmt->fetch()) {
        $houses[] = $house;
    }
    $stmt->close();
    // clean tblItemHistoryHourly, tblPetHistoryHourly, tblItemHistoryDaily
    $sqlPatternHourly = 'delete from tbl%sHistoryHourly where house = %d and `when` < \'%s\'';
    $sqlPatternDaily = 'delete from tblItemHistoryDaily where house = %d and `when` < \'%s\'';
    for ($hx = 0; $hx < count($houses); $hx++) {
        heartbeat();
        if ($caughtKill) {
            return;
        }
        $house = $houses[$hx];
        if (!MCHouseLock($house)) {
            continue;
        }
        $ssDate = '';
        $cutoffDateHourly = date('Y-m-d', strtotime('' . HISTORY_DAYS . ' days ago'));
        $cutOffDateDaily = date('Y-m-d', strtotime('' . HISTORY_DAYS_DEEP . ' days ago'));
        $stmt = $db->prepare('SELECT date(min(`updated`)) FROM (SELECT `updated` FROM tblSnapshot WHERE house = ? AND `flags` & 1 = 0 ORDER BY updated DESC LIMIT ?) aa');
        $maxSnapshots = 24 * HISTORY_DAYS;
        $stmt->bind_param('ii', $house, $maxSnapshots);
        $stmt->execute();
        $stmt->bind_result($ssDate);
        $gotDate = $stmt->fetch() === true;
        $stmt->close();
        if (!$gotDate || is_null($ssDate)) {
            DebugMessage("{$house} has no snapshots, skipping item history!");
            MCHouseUnlock($house);
            continue;
        }
        if (strtotime($ssDate) < strtotime($cutoffDateHourly)) {
            $cutoffDateHourly = $ssDate;
        }
        if (!$caughtKill) {
            $rowCount = DeleteLimitLoop($db, sprintf($sqlPatternHourly, 'Item', $house, $cutoffDateHourly));
            DebugMessage("{$rowCount} item hourly history rows deleted from house {$house} since {$cutoffDateHourly}");
        }
        if (!$caughtKill) {
            $rowCount = DeleteLimitLoop($db, sprintf($sqlPatternHourly, 'Pet', $house, $cutoffDateHourly));
            DebugMessage("{$rowCount} pet hourly history rows deleted from house {$house} since {$cutoffDateHourly}");
        }
        if (!$caughtKill) {
            $rowCount = DeleteLimitLoop($db, sprintf($sqlPatternDaily, $house, $cutOffDateDaily));
            DebugMessage("{$rowCount} item history daily rows deleted from house {$house} since {$cutOffDateDaily}");
        }
        MCHouseUnlock($house);
    }
    if ($caughtKill) {
        return;
    }
    // clean tblItemExpired
    for ($hx = 0; $hx < count($houses); $hx++) {
        heartbeat();
        if ($caughtKill) {
            return;
        }
        $house = $houses[$hx];
        if (!MCHouseLock($house)) {
            continue;
        }
        $cutoffDate = date('Y-m-d H:i:s', strtotime('' . (HISTORY_DAYS * 2 + 3) . ' days ago'));
        $sql = sprintf('delete from tblItemExpired where house = %d and `when` < \'%s\'', $house, $cutoffDate);
        $rowCount = DeleteLimitLoop($db, $sql);
        DebugMessage(sprintf('%d expired item rows removed from house %d since %s', $rowCount, $house, $cutoffDate));
        MCHouseUnlock($house);
    }
    if ($caughtKill) {
        return;
    }
    $rowCount = 0;
    DebugMessage('Clearing out old seller history');
    $cutoffDateHourly = date('Y-m-d', strtotime('' . HISTORY_DAYS . ' days ago'));
    $sql = sprintf('delete from tblSellerHistoryHourly where `when` < \'%s\'', $cutoffDateHourly);
    $rowCount += DeleteLimitLoop($db, $sql);
    DebugMessage("{$rowCount} seller history rows deleted in total");
    $rowCount = 0;
    DebugMessage('Clearing out old seller item history');
    $sql = 'delete from tblSellerItemHistory where snapshot < timestampadd(day, -' . HISTORY_DAYS . ', now())';
    $rowCount += DeleteLimitLoop($db, $sql);
    DebugMessage("{$rowCount} seller item history rows deleted in total");
    $rowCount = 0;
    $old = date('Y-m-d H:i:s', time() - SUBSCRIPTION_SESSION_LENGTH - 172800);
    // 2 days older than oldest cookie age
    DebugMessage('Clearing out user sessions older than ' . $old);
    $sql = "delete from tblUserSession where lastseen < '{$old}'";
    $rowCount += DeleteLimitLoop($db, $sql, 500);
    DebugMessage("{$rowCount} user session rows deleted in total");
    for ($hx = 0; $hx < count($houses); $hx++) {
        heartbeat();
        if ($caughtKill) {
            return;
        }
        $house = $houses[$hx];
        if (!MCHouseLock($house)) {
            continue;
        }
        $cutoffDate = date('Y-m-d H:i:s', strtotime('' . (HISTORY_DAYS + 3) . ' days ago'));
        $sql = sprintf('DELETE FROM tblSnapshot WHERE house = %d AND updated < \'%s\'', $house, $cutoffDate);
        $db->query($sql);
        DebugMessage(sprintf('%d snapshot rows removed from house %d since %s', $db->affected_rows, $house, $cutoffDate));
        MCHouseUnlock($house);
    }
}
예제 #23
0
파일: incl.php 프로젝트: erorus/newsstand
function GetLang($lang)
{
    static $locales = [];
    if (isset($locales[$lang])) {
        return $locales[$lang];
    }
    $path = __DIR__ . '/../public/js/locale/' . strtolower($lang) . '.json';
    if (!file_exists($path)) {
        $locales[$lang] = false;
        return $locales[$lang];
    }
    $json = json_decode(file_get_contents($path), true);
    if (json_last_error() != JSON_ERROR_NONE) {
        DebugMessage("Error decoding JSON at {$path}: " . json_last_error_msg());
    }
    if ($lang != 'enus') {
        $enus = GetLang('enus');
        $json = array_replace_recursive($enus, $json);
    }
    $locales[$lang] = $json;
    return $locales[$lang];
}
예제 #24
0
function SendTweet($msg)
{
    if ($msg == '') {
        return false;
    }
    DebugMessage('Sending tweet of ' . strlen($msg) . " chars:\n" . $msg);
    global $twitterCredentials;
    if ($twitterCredentials === false) {
        return true;
    }
    $params = array();
    $params['status'] = $msg;
    $oauth = new OAuth($twitterCredentials['consumerKey'], $twitterCredentials['consumerSecret']);
    $oauth->setToken($twitterCredentials['WoWTokens']['accessToken'], $twitterCredentials['WoWTokens']['accessTokenSecret']);
    $url = 'https://api.twitter.com/1.1/statuses/update.json';
    try {
        $didWork = $oauth->fetch($url, $params, 'POST', array('Connection' => 'close'));
    } catch (OAuthException $e) {
        $didWork = false;
    }
    $ri = $oauth->getLastResponseInfo();
    $r = $oauth->getLastResponse();
    if ($didWork && $ri['http_code'] == '200') {
        $json = json_decode($r, true);
        if (json_last_error() == JSON_ERROR_NONE) {
            if (isset($json['id_str'])) {
                return $json['id_str'];
            }
        }
        return true;
    }
    if (isset($ri['http_code'])) {
        DebugMessage('Twitter returned HTTP code ' . $ri['http_code'], E_USER_WARNING);
    } else {
        DebugMessage('Twitter returned unknown HTTP code', E_USER_WARNING);
    }
    DebugMessage('Twitter returned: ' . print_r($ri, true), E_USER_WARNING);
    DebugMessage('Twitter returned: ' . print_r($r, true), E_USER_WARNING);
    return false;
}
예제 #25
0
function DBQueryWithError(&$db, $sql)
{
    $queryOk = $db->query($sql);
    if (!$queryOk) {
        DebugMessage("SQL error: " . $db->errno . ' ' . $db->error . " - " . substr(preg_replace('/[\\r\\n]/', ' ', $sql), 0, 500), E_USER_WARNING);
    }
    return $queryOk;
}
예제 #26
0
<?php

$memcache = new Memcache();
if (!$memcache->connect('127.0.0.1', 11211)) {
    DebugMessage('Cannot connect to memcached!', E_USER_ERROR);
}
$memcache->setCompressThreshold(50 * 1024);
function MCGet($key)
{
    global $memcache;
    return $memcache->get('rp_' . $key);
}
function MCSet($key, $val, $expire = 10800)
{
    global $memcache;
    return $memcache->set('rp_' . $key, $val, false, $expire);
}
function MCAdd($key, $val, $expire = 10800)
{
    global $memcache;
    return $memcache->add('rp_' . $key, $val, false, $expire);
}
function MCDelete($key)
{
    global $memcache;
    return $memcache->delete('rp_' . $key);
}
예제 #27
0
파일: incl.php 프로젝트: erorus/realmpop
function RunMeNTimes($howMany = 1)
{
    global $argv;
    if (php_sapi_name() != 'cli') {
        DebugMessage('Cannot run once if not CLI', E_USER_WARNING);
        return;
    }
    if (intval(shell_exec('ps -o args -C php | grep ' . escapeshellarg(implode(' ', $argv)) . ' | wc -l')) > $howMany) {
        die;
    }
}
예제 #28
0
function UploadTweetMedia($data)
{
    global $twitterCredentials;
    if ($twitterCredentials === false) {
        return false;
    }
    $boundary = '';
    $mimedata['media'] = "content-disposition: form-data; name=\"media\"\r\nContent-Type: image/png\r\nContent-Transfer-Encoding: binary\r\n\r\n" . $data;
    while ($boundary == '') {
        for ($x = 0; $x < 16; $x++) {
            $boundary .= chr(rand(ord('a'), ord('z')));
        }
        foreach ($mimedata as $d) {
            if (strpos($d, $boundary) !== false) {
                $boundary = '';
            }
        }
    }
    $mime = '';
    foreach ($mimedata as $d) {
        $mime .= "--{$boundary}\r\n{$d}\r\n";
    }
    $mime .= "--{$boundary}--\r\n";
    $oauth = new OAuth($twitterCredentials['consumerKey'], $twitterCredentials['consumerSecret']);
    $oauth->setToken($twitterCredentials[TWITTER_ACCOUNT]['accessToken'], $twitterCredentials[TWITTER_ACCOUNT]['accessTokenSecret']);
    $url = 'https://upload.twitter.com/1.1/media/upload.json';
    $requestHeader = $oauth->getRequestHeader('POST', $url);
    $inHeaders = ["Authorization: {$requestHeader}", 'Content-Type: multipart/form-data; boundary=' . $boundary];
    $outHeaders = [];
    $ret = \Newsstand\HTTP::Post($url, $mime, $inHeaders, $outHeaders);
    if ($ret) {
        $json = json_decode($ret, true);
        if (json_last_error() == JSON_ERROR_NONE) {
            if (isset($json['media_id_string'])) {
                return $json['media_id_string'];
            } else {
                DebugMessage('Parsed JSON response from post to twitter, no media id', E_USER_WARNING);
                DebugMessage(print_r($json, true), E_USER_WARNING);
                return false;
            }
        } else {
            DebugMessage('Non-JSON response from post to twitter', E_USER_WARNING);
            DebugMessage($ret, E_USER_WARNING);
            return false;
        }
    } else {
        DebugMessage('No/bad response from post to twitter', E_USER_WARNING);
        DebugMessage(print_r($outHeaders, true), E_USER_WARNING);
        return false;
    }
}
예제 #29
0
function MakeZip($zipPath = false)
{
    DebugMessage('Making zip file..');
    $zipFilename = tempnam('/tmp', 'addonzip');
    $zip = new ZipArchive();
    if (!$zip->open($zipFilename, ZipArchive::CREATE)) {
        @unlink($zipFilename);
        DebugMessage('Could not create zip file', E_USER_ERROR);
    }
    $tocFile = file_get_contents('../addon/TheUndermineJournal.toc');
    $tocFile = sprintf($tocFile, date('D, F j'), date('Ymd'));
    $zip->addFromString("TheUndermineJournal/TheUndermineJournal.toc", $tocFile);
    RecursiveAddToZip($zip, '../addon/libs/', 'TheUndermineJournal/libs/');
    $zip->addFile('../addon/GetDetailedItemLevelInfo.lua', "TheUndermineJournal/GetDetailedItemLevelInfo.lua");
    $zip->addFile('../addon/BonusSets.lua', "TheUndermineJournal/BonusSets.lua");
    $zip->addFile('../addon/TheUndermineJournal.lua', "TheUndermineJournal/TheUndermineJournal.lua");
    $zip->addFile('../addon/MarketData-US.lua', "TheUndermineJournal/MarketData-US.lua");
    $zip->addFile('../addon/MarketData-EU.lua', "TheUndermineJournal/MarketData-EU.lua");
    //$zip->addFromString("TheUndermineJournal/SpellToItem.lua",getspelltoitemlua());
    $zip->close();
    if (!$zipPath) {
        $zipPath = '../addon/TheUndermineJournal.zip';
    }
    rename($zipFilename, $zipPath);
}
예제 #30
0
    $stmt->bind_param('s', $region);
    $stmt->execute();
    $result = $stmt->get_result();
    $slugs = DBMapArray($result, null);
    $stmt->close();
    foreach ($slugs as $slug) {
        if ($caughtKill) {
            break;
        }
        file_put_contents($publicDir . '/' . strtolower($region) . '-' . $slug . '.html', cookhtml($region, $slug));
        $siteMap .= '<url><loc>https://realmpop.com/' . strtolower($region) . '-' . $slug . '.html</loc><priority>0.5</priority><changefreq>weekly</changefreq></url>' . "\n";
    }
}
$siteMap .= "</urlset>";
file_put_contents($publicDir . '/sitemap.xml', $siteMap);
DebugMessage('Done! Started ' . TimeDiff($startTime));
// PRETTYREALM SLUG REALMBIO REALMSET JSONSIZE
function cookhtml($realmset, $slug = '')
{
    global $publicDir, $db;
    global $htmlheader, $htmlrealm, $htmlend, $htmlrealmset;
    $jsonfn = $publicDir . '/' . strtolower($realmset) . ($slug != '' ? '-' : '') . $slug . '.json';
    $jsonsize = file_exists($jsonfn) ? filesize($jsonfn) : 0;
    if ($slug != '') {
        $html = $htmlheader . $htmlrealm . $htmlend;
        $realmset = substr(strtoupper($realmset), 0, 2);
        $realmslug = substr($slug, 0, 45);
        $sql = <<<EOF
select r.*, if(r.region='US',if(locale='pt_BR', 'Brazil', if(locale='es_MX', 'Latin America', if(timezone like 'Australia/%', 'Oceanic', 'United States'))),
case locale
when 'de_DE' then 'German'