function GetBattleNetURL($region, $path) { $region = trim(strtolower($region)); if (substr($path, 0, 1) == '/') { $path = substr($path, 1); } $start = microtime(true); $finalUrl = ''; while (!$finalUrl && $start + 5 > microtime(true)) { $cacheKey = 'BattleNetKeyUsage'; if (!MCAdd($cacheKey . '_critical', 1, 5 * BATTLE_NET_REQUEST_PERIOD)) { usleep(50000); continue; } $apiHits = MCGet($cacheKey); if ($apiHits === false) { $apiHits = []; } $hitCount = count($apiHits); if ($hitCount >= BATTLE_NET_REQUEST_LIMIT) { $now = microtime(true); while ($apiHits[0] < $now && $now < $apiHits[0] + BATTLE_NET_REQUEST_PERIOD) { usleep(50000); $now = microtime(true); } } $apiHits[] = microtime(true); $hitCount++; if ($hitCount > BATTLE_NET_REQUEST_LIMIT) { array_splice($apiHits, 0, $hitCount - BATTLE_NET_REQUEST_LIMIT); } MCSet($cacheKey, $apiHits, 10 * BATTLE_NET_REQUEST_PERIOD); MCDelete($cacheKey . '_critical'); $pattern = $region == 'cn' ? 'https://api.battlenet.com.%s/%s%sapikey=%s' : 'https://%s.api.battle.net/%s%sapikey=%s'; $finalUrl = sprintf($pattern, $region, $path, strpos($path, '?') !== false ? '&' : '?', BATTLE_NET_KEY); } return $finalUrl ? $finalUrl : false; }
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; }
function SetWatch($loginState, $type, $item, $bonusSet, $region, $house, $direction, $quantity, $price) { $userId = $loginState['id']; $type = $type == 'species' ? 'species' : 'item'; $subType = $type == 'species' ? 'breed' : 'bonusset'; $item = intval($item, 10); if (!$item) { return false; } $bonusSet = intval($bonusSet, 10); if ($bonusSet < 0) { $bonusSet = null; } $house = intval($house, 10); if ($house <= 0) { if (!in_array($region, ['US', 'EU'])) { return false; } $house = null; } else { $region = null; } if (!in_array($direction, ['Under', 'Over'])) { return false; } $quantity = intval($quantity, 10); if ($quantity < 0) { $quantity = null; } $price = intval($price, 10); if ($price < 0) { $price = null; } if (!is_null($quantity)) { if (is_null($price)) { // qty available query if ($quantity == 0 && $direction == 'Under') { // qty never under 0 return false; } } else { // cost to buy $quantity is $direction $price if ($quantity == 0) { // must buy at least 1 return false; } if ($price == 0 && $direction == 'Under') { // price never under 0 return false; } } } else { // market price queries if (is_null($price)) { // both qty and price null return false; } if ($price <= 0) { // price never under 0 return false; } } $loops = 0; while (!MCAdd(SUBSCRIPTION_WATCH_LOCK_CACHEKEY . $userId, 1, 15)) { usleep(250000); if ($loops++ >= 120) { // 30 seconds return false; } } $db = DBConnect(); $db->begin_transaction(); $stmt = $db->prepare('select seq, region, house, direction, quantity, price from tblUserWatch where user = ? and ' . $type . ' = ? and ifnull(' . $subType . ',0) = ifnull(?,0) and deleted is null for update'); $stmt->bind_param('iii', $userId, $item, $bonusSet); $stmt->execute(); $result = $stmt->get_result(); $curWatches = DBMapArray($result); $stmt->close(); $fail = false; $cnt = count($curWatches); $fail |= $cnt > SUBSCRIPTION_WATCH_LIMIT_PER; foreach ($curWatches as $curWatch) { $fail |= !is_null($curWatch['region']) && $curWatch['region'] == $region && $curWatch['direction'] == $direction && $curWatch['quantity'] == $quantity && $curWatch['price'] == $price; $fail |= is_null($region) && is_null($curWatch['region']) && $curWatch['house'] == $house && $curWatch['direction'] == $direction && $curWatch['quantity'] == $quantity && $curWatch['price'] == $price; } if ($fail) { $db->rollback(); MCDelete(SUBSCRIPTION_WATCH_LOCK_CACHEKEY . $userId); return false; } if (GetWatchCount($userId, $db) >= SUBSCRIPTION_WATCH_LIMIT_TOTAL) { $db->rollback(); MCDelete(SUBSCRIPTION_WATCH_LOCK_CACHEKEY . $userId); return false; } $stmt = $db->prepare('update tblUser set watchsequence = last_insert_id(watchsequence+1) where id = ?'); $stmt->bind_param('i', $userId); $stmt->execute(); $stmt->close(); $seq = $db->insert_id; $stmt = $db->prepare('insert into tblUserWatch (user, seq, region, house, ' . $type . ', ' . $subType . ', direction, quantity, price, created) values (?,?,?,?,?,?,?,?,?,NOW())'); $stmt->bind_param('iisiiisii', $userId, $seq, $region, $house, $item, $bonusSet, $direction, $quantity, $price); $stmt->execute(); $stmt->close(); $cnt = $db->affected_rows; if ($cnt == 0) { $db->rollback(); MCDelete(SUBSCRIPTION_WATCH_LOCK_CACHEKEY . $userId); return false; } $db->commit(); MCDelete(SUBSCRIPTION_WATCH_LOCK_CACHEKEY . $userId); $cacheKeyPrefix = defined('SUBSCRIPTION_' . strtoupper($type) . '_CACHEKEY') ? constant('SUBSCRIPTION_' . strtoupper($type) . '_CACHEKEY') : 'subunknown_' . substr($type, 0, 20); MCDelete($cacheKeyPrefix . $userId . '_' . $item); MCDelete($cacheKeyPrefix . $userId); MCDelete(SUBSCRIPTION_WATCH_COUNT_CACHEKEY . $userId); return true; }
function SendUserMessage($userId, $messageType, $subject, $message) { $loops = 0; while (!MCAdd(SUBSCRIPTION_MESSAGES_CACHEKEY . "lock_{$userId}", 1, 15)) { usleep(250000); if ($loops++ >= 120) { // 30 seconds return false; } } $db = DBConnect(true); $seq = 0; $cnt = 0; $stmt = $db->prepare('select ifnull(max(seq),0)+1, count(*) from tblUserMessages where user = ?'); $stmt->bind_param('i', $userId); $stmt->execute(); $stmt->bind_result($seq, $cnt); $stmt->fetch(); $stmt->close(); $stmt = $db->prepare('INSERT INTO tblUserMessages (user, seq, created, type, subject, message) VALUES (?, ?, NOW(), ?, ?, ?)'); $stmt->bind_param('iisss', $userId, $seq, $messageType, $subject, $message); $success = $stmt->execute(); $stmt->close(); if ($success) { $cnt++; } if ($cnt > SUBSCRIPTION_MESSAGES_MAX) { $stmt = $db->prepare('delete from tblUserMessages where user = ? order by seq asc limit ?'); $cnt = $cnt - SUBSCRIPTION_MESSAGES_MAX; $stmt->bind_param('ii', $userId, $cnt); $stmt->execute(); $stmt->close(); } MCDelete(SUBSCRIPTION_MESSAGES_CACHEKEY . "lock_{$userId}"); if (!$success) { DebugMessage("Error adding user message: " . $db->error); $db->close(); return false; } MCDelete(SUBSCRIPTION_MESSAGES_CACHEKEY . $userId); MCDelete(SUBSCRIPTION_MESSAGES_CACHEKEY . $userId . '_' . $seq); $stmt = $db->prepare('select name, email, locale from tblUser where id = ? and email is not null and emailverification is null'); $stmt->bind_param('i', $userId); $stmt->execute(); $name = $address = $locale = ''; $stmt->bind_result($name, $address, $locale); if (!$stmt->fetch()) { $address = false; } $stmt->close(); if ($address) { NewsstandMail($address, $name, $subject, $message, $locale); } UpdateUserRss($userId, $db); $db->close(); return $seq; }