Esempio n. 1
0
function HTMLToBBCode($aString)
{
    $Text = $aString;
    $Text = preg_replace('/<a href="(.*)"\\><\\/a\\>/', '[url]\\1[/url]', $Text);
    $Text = preg_replace('/<a href="(.*)"\\>(.*)<\\/a\\>/', '[url=\'\\1\']\\2[/url]', $Text);
    $Text = preg_replace('/<b>(.*)<\\/b\\>/', '[b]\\1[/b]', $Text);
    $Text = preg_replace('/<i>(.*)<\\/i\\>/', '[i]\\1[/i]', $Text);
    $Text = preg_replace('/<img src=\'(.*)\'\\/>/', '[img]\\1[/img]', $Text);
    $Text = preg_replace('/<br\\/>/', "\n", $Text);
    return xmlToUTF8($Text);
}
Esempio n. 2
0
function api_query_location($aParameter)
{
    $aGames = getParamFrom($aParameter, 'games', '');
    $aUTF8 = getParamFrom($aParameter, 'utf8', false);
    $Parameters = array();
    $Conditions = array();
    // Filter games
    if ($aGames != '') {
        $Games = explode(',', $aGames);
        $GameOptions = array();
        foreach ($Games as $Game) {
            array_push($GameOptions, 'Game=?');
            array_push($Parameters, $Game);
        }
        array_push($Conditions, $GameOptions);
    }
    // Build where clause
    $WhereString = '';
    if (count($Conditions) > 0) {
        foreach ($Conditions as &$Part) {
            if (is_array($Part)) {
                $Part = '(' . implode(' OR ', $Part) . ')';
            }
        }
        $WhereString = 'WHERE ' . implode(' AND ', $Conditions) . ' ';
    }
    // Query
    $Connector = Connector::getInstance();
    $LocationQuery = $Connector->prepare('SELECT * FROM `' . RP_TABLE_PREFIX . 'Location` ' . $WhereString . ' ORDER BY Name');
    foreach ($Parameters as $Index => $Value) {
        if (is_numeric($Value)) {
            $LocationQuery->bindValue($Index + 1, $Value, PDO::PARAM_INT);
        } else {
            $LocationQuery->bindValue($Index + 1, $Value, PDO::PARAM_STR);
        }
    }
    // Build result
    $Result = array();
    $LocationQuery->loop(function ($LocationRow) use(&$Result, $aUTF8) {
        array_push($Result, array('Id' => $LocationRow['LocationId'], 'Name' => $aUTF8 ? xmlToUTF8($LocationRow['Name']) : $LocationRow['Name'], 'GameId' => $LocationRow['Game'], 'Image' => $LocationRow['Image']));
    });
    return $Result;
}
Esempio n. 3
0
 public function post($aSubject, $aMessage)
 {
     $Connector = $this->getConnector();
     $Timestamp = time();
     // Fetch user
     try {
         do {
             $Connector->beginTransaction();
             $UserQuery = $Connector->prepare('SELECT username FROM `wcf' . WBB_TABLE_PREFIX . '_user` ' . 'WHERE userID=:UserId LIMIT 1');
             $UserQuery->BindValue(':UserId', WBB_POSTAS, PDO::PARAM_INT);
             $UserData = $UserQuery->fetchFirst();
             // Create topic
             $ThreadQuery = $Connector->prepare('INSERT INTO `wbb' . WBB_TABLE_PREFIX . '_thread` ' . '(boardId, userId, topic, time, username, lastPostTime, lastPoster, lastPosterID) VALUES ' . '(:BoardId, :UserId, :Subject, :Now, :Username, :Now, :Username, :UserId)');
             $ThreadQuery->BindValue(':BoardId', WBB_POSTTO, PDO::PARAM_INT);
             $ThreadQuery->BindValue(':UserId', WBB_POSTAS, PDO::PARAM_INT);
             $ThreadQuery->BindValue(':Subject', xmlToUTF8($aSubject), PDO::PARAM_STR);
             $ThreadQuery->BindValue(':Now', $Timestamp, PDO::PARAM_INT);
             $ThreadQuery->BindValue(':Username', $UserData['username'], PDO::PARAM_STR);
             $ThreadQuery->execute(true);
             $ThreadId = $Connector->lastInsertId();
             // Create post
             $FormattedMessage = HTMLToBBCode($aMessage);
             $PostQuery = $Connector->prepare('INSERT INTO `wbb' . WBB_TABLE_PREFIX . '_post` ' . '(threadId, time, username, userId, message) VALUES ' . '(:ThreadId, :Now, :Username, :UserId, :Text)');
             $PostQuery->BindValue(':ThreadId', $ThreadId, PDO::PARAM_INT);
             $PostQuery->BindValue(':Now', $Timestamp, PDO::PARAM_INT);
             $PostQuery->BindValue(':Username', $UserData['username'], PDO::PARAM_STR);
             $PostQuery->BindValue(':UserId', WBB_POSTAS, PDO::PARAM_INT);
             $PostQuery->BindValue(':Text', $FormattedMessage, PDO::PARAM_STR);
             $PostQuery->execute(true);
             $PostId = $Connector->lastInsertId();
             // Finish topic
             $TopicFinishQuery = $Connector->prepare('UPDATE `wbb' . WBB_TABLE_PREFIX . '_thread` ' . 'SET firstPostID = :PostId, lastPostID = :PostId ' . 'WHERE threadID = :ThreadId LIMIT 1');
             $TopicFinishQuery->BindValue(':PostId', $PostId, PDO::PARAM_INT);
             $TopicFinishQuery->BindValue(':ThreadId', $ThreadId, PDO::PARAM_INT);
             $TopicFinishQuery->execute(true);
             // Update board
             $BoardQuery = $Connector->prepare('UPDATE `wbb' . WBB_TABLE_PREFIX . '_board_last_post` ' . 'SET threadID = :ThreadId ' . 'WHERE boardId = :BoardId LIMIT 1');
             $BoardQuery->BindValue(':ThreadId', $ThreadId, PDO::PARAM_INT);
             $BoardQuery->BindValue(':BoardId', WBB_POSTTO, PDO::PARAM_INT);
             $BoardQuery->execute(true);
         } while (!$Connector->commit());
     } catch (PDOException $Exception) {
         $Connector->rollBack();
         throw $Exception;
     }
 }
Esempio n. 4
0
function api_query_raid($aParameter)
{
    // Assemble paramters
    $aStart = getParamFrom($aParameter, 'start', 0);
    $aEnd = getParamFrom($aParameter, 'end', 0x7fffffff);
    $aLimit = getParamFrom($aParameter, 'limit', 0);
    $aOffset = getParamFrom($aParameter, 'offset', 0);
    $aRaid = getParamFrom($aParameter, 'raid', '');
    $aLocation = getParamFrom($aParameter, 'location', '');
    $aGames = getParamFrom($aParameter, 'games', '');
    $aFetchFull = getParamFrom($aParameter, 'full', true);
    $aFetchFree = getParamFrom($aParameter, 'free', true);
    $aFetchOpen = getParamFrom($aParameter, 'open', true);
    $aFetchClosed = getParamFrom($aParameter, 'closed', false);
    $aFetchCanceled = getParamFrom($aParameter, 'canceled', false);
    $aAddAttends = getParamFrom($aParameter, 'attends', false);
    $aDesc = getParamFrom($aParameter, 'desc', false);
    $aUTF8 = getParamFrom($aParameter, 'utf8', false);
    // Build query
    $Fields = array('`inner_select`.*', '`' . RP_TABLE_PREFIX . 'Attendance`.Status', '`' . RP_TABLE_PREFIX . 'Attendance`.Role');
    $Conditions = array('`' . RP_TABLE_PREFIX . 'Raid`.Start > FROM_UNIXTIME(?)', '`' . RP_TABLE_PREFIX . 'Raid`.Start < FROM_UNIXTIME(?)');
    $Parameters = array($aStart, $aEnd);
    $TableQuery = 'SELECT' . ' `' . RP_TABLE_PREFIX . 'Raid`.*,' . ' UNIX_TIMESTAMP(`' . RP_TABLE_PREFIX . 'Raid`.Start) AS StartUTC,' . ' UNIX_TIMESTAMP(`' . RP_TABLE_PREFIX . 'Raid`.End) AS EndUTC' . ' FROM `' . RP_TABLE_PREFIX . 'Raid` ' . ' LEFT JOIN `' . RP_TABLE_PREFIX . 'Location` USING (LocationId) ';
    // Specific raids
    if ($aRaid != '') {
        $Raids = explode(',', $aRaid);
        foreach ($Raids as &$RaidId) {
            $RaidId = intval($RaidId);
        }
        if (count($Raids) == 1) {
            array_push($Conditions, '`' . RP_TABLE_PREFIX . 'Raid`.RaidId=?');
            array_push($Parameters, $Raids[0]);
        } else {
            if (count($Raids) > 1) {
                array_push($Conditions, '`' . RP_TABLE_PREFIX . 'Raid`.RaidId IN (' . implode(',', $Raids) . ')');
            }
        }
    }
    // Merge locations if required
    if ($aLocation != '') {
        $Locations = explode(',', $aLocation);
        $LocationById = array();
        $LocationByName = array();
        $LocationConditions = array();
        // Sort into ids and names
        foreach ($Locations as $Location) {
            if (is_numeric($Location)) {
                array_push($LocationById, intval($Location));
            } else {
                array_push($LocationByName, $Location);
            }
        }
        // Build id based condition
        if (count($LocationById) == 1) {
            array_push($LocationConditions, '`' . RP_TABLE_PREFIX . 'Location`.LocationId=?');
            array_push($Parameters, $LocationById[0]);
        } else {
            if (count($LocationById) > 1) {
                array_push($LocationConditions, '`' . RP_TABLE_PREFIX . 'Location`.LocationId IN (' . implode(',', $LocationById) . ')');
            }
        }
        // Build name based condition
        if (count($LocationByName) == 1) {
            array_push($LocationConditions, '`' . RP_TABLE_PREFIX . 'Location`.Name=?');
            array_push($Parameters, $LocationByName[0]);
        } else {
            if (count($LocationByName) > 1) {
                array_push($LocationConditions, '`' . RP_TABLE_PREFIX . 'Location`.Name IN ("' . implode('","', $LocationByName) . '")');
            }
        }
        array_push($Conditions, $LocationConditions);
    }
    // Raid status
    if (!$aFetchOpen || !$aFetchClosed || !$aFetchCanceled) {
        $StatusConditions = array();
        if ($aFetchOpen) {
            array_push($StatusConditions, '`' . RP_TABLE_PREFIX . 'Raid`.Stage = "open"');
        }
        if ($aFetchClosed) {
            array_push($StatusConditions, '`' . RP_TABLE_PREFIX . 'Raid`.Stage = "locked"');
        }
        if ($aFetchCanceled) {
            array_push($StatusConditions, '`' . RP_TABLE_PREFIX . 'Raid`.Stage = "canceled"');
        }
        array_push($Conditions, $StatusConditions);
    }
    // Filter games
    if ($aGames != '') {
        $Games = explode(',', $aGames);
        $GameOptions = array();
        foreach ($Games as $Game) {
            array_push($GameOptions, '`' . RP_TABLE_PREFIX . 'Location`.Game=?');
            array_push($Parameters, $Game);
        }
        array_push($Conditions, $GameOptions);
    }
    // Build where part
    $WhereString = '';
    if (count($Conditions) > 0) {
        foreach ($Conditions as &$Part) {
            if (is_array($Part)) {
                $Part = '(' . implode(' OR ', $Part) . ')';
            }
        }
        $WhereString = ' WHERE ' . implode(' AND ', $Conditions);
    }
    // Build limit part
    $LimitString = '';
    if ($aLimit > 0) {
        $LimitString = ' LIMIT ' . intval($aOffset) . ',' . intval($aLimit);
    }
    // Build order part
    $OrderString = ' ORDER BY' . ' `' . RP_TABLE_PREFIX . 'Raid`.Start ' . ($aDesc ? 'DESC' : 'ASC') . ',' . ' `' . RP_TABLE_PREFIX . 'Raid`.RaidId ' . ($aDesc ? 'DESC' : 'ASC');
    // Merge attendance information (outer select)
    $AttendanceJoin = 'LEFT JOIN `' . RP_TABLE_PREFIX . 'Attendance` USING (RaidId) ';
    if ($aAddAttends === true) {
        $AttendanceJoin .= 'LEFT JOIN `' . RP_TABLE_PREFIX . 'User` USING (UserId) ';
        $AttendanceJoin .= 'LEFT JOIN `' . RP_TABLE_PREFIX . 'Character` USING (CharacterId) ';
        $Fields = array_merge($Fields, array('`' . RP_TABLE_PREFIX . 'Attendance`.Class', '`' . RP_TABLE_PREFIX . 'Attendance`.Comment', '`' . RP_TABLE_PREFIX . 'User`.UserId', '`' . RP_TABLE_PREFIX . 'User`.ExternalBinding AS BindingId', '`' . RP_TABLE_PREFIX . 'User`.ExternalId AS BoundUserId', '`' . RP_TABLE_PREFIX . 'Character`.Name AS CharacterName', '`' . RP_TABLE_PREFIX . 'Character`.Class AS CharacterClasses', '`' . RP_TABLE_PREFIX . 'Character`.Mainchar AS CharacterIsMain', '`' . RP_TABLE_PREFIX . 'Character`.Role1 AS CharacterRole1', '`' . RP_TABLE_PREFIX . 'Character`.Role2 AS CharacterRole2'));
    }
    // Execute query
    $QueryString = 'SELECT ' . implode(',', $Fields) . ' FROM (' . $TableQuery . $WhereString . $OrderString . $LimitString . ') AS inner_select ' . $AttendanceJoin;
    //Out::getInstance()->pushValue('debug', $QueryString);
    $Connector = Connector::getInstance();
    $RaidQuery = $Connector->prepare($QueryString);
    foreach ($Parameters as $Index => $Value) {
        //Out::getInstance()->pushValue('debug', $Value);
        if (is_numeric($Value)) {
            $RaidQuery->bindValue($Index + 1, $Value, PDO::PARAM_INT);
        } else {
            $RaidQuery->bindValue($Index + 1, $Value, PDO::PARAM_STR);
        }
    }
    // Prepare results
    $LastRaidId = 0;
    $Result = array();
    $Raid = array();
    $RaidQuery->loop(function ($aRaidRow) use(&$LastRaidId, &$Raid, &$Result, $aAddAttends, $aFetchFull, $aFetchFree, $aUTF8) {
        if ($aRaidRow['RaidId'] != $LastRaidId) {
            if (api_filter_raid($Raid, $aFetchFull, $aFetchFree)) {
                array_push($Result, $Raid);
            }
            // Generate Raid
            $LastRaidId = $aRaidRow['RaidId'];
            $Raid = array('RaidId' => $aRaidRow['RaidId'], 'LocationId' => $aRaidRow['LocationId'], 'Status' => $aRaidRow['Stage'], 'Size' => $aRaidRow['Size'], 'Start' => $aRaidRow['StartUTC'], 'End' => $aRaidRow['EndUTC'], 'Description' => $aUTF8 ? xmlToUTF8($aRaidRow['Description']) : $aRaidRow['Description'], 'Slots' => array_combine(explode(':', $aRaidRow['SlotRoles']), explode(':', $aRaidRow['SlotCount'])), 'SetToRaid' => array(), 'Available' => array(), 'Absent' => 0);
            if ($aAddAttends) {
                $Raid['Attends'] = array();
            }
            foreach ($Raid['Slots'] as $Role => $Max) {
                $Raid['SetToRaid'][$Role] = 0;
                $Raid['Available'][$Role] = 0;
            }
        }
        // Count available / absent
        if ($aRaidRow['Role'] !== null && $aRaidRow['Role'] !== '') {
            switch ($aRaidRow['Status']) {
                case 'ok':
                    ++$Raid['SetToRaid'][$aRaidRow['Role']];
                    // ok counts as available, too
                // ok counts as available, too
                case 'available':
                    ++$Raid['Available'][$aRaidRow['Role']];
                    break;
                case 'undecided':
                    // TODO: Need to query all available users to return undecided
                    break;
                case 'unavailable':
                default:
                    ++$Raid['Absent'];
                    break;
            }
        }
        // Add attends if requested
        if ($aAddAttends && $aRaidRow['Status'] !== null) {
            $Attend = array('UserId' => $aRaidRow['UserId'], 'BindingId' => $aRaidRow['BindingId'], 'BoundUserId' => $aRaidRow['BoundUserId'], 'Status' => $aRaidRow['Status'], 'Role' => $aRaidRow['Role'], 'Class' => $aRaidRow['Class'], 'Comment' => $aUTF8 ? xmlToUTF8($aRaidRow['Comment']) : $aRaidRow['Comment'], 'CharacterName' => $aUTF8 ? xmlToUTF8($aRaidRow['CharacterName']) : $aRaidRow['CharacterName'], 'CharacterIsMain' => $aRaidRow['CharacterIsMain'], 'CharacterClasses' => explode(':', $aRaidRow['CharacterClasses']), 'CharacterRoles' => array($aRaidRow['CharacterRole1'], $aRaidRow['CharacterRole2']));
            array_push($Raid['Attends'], $Attend);
        }
    });
    // Add remaining raid
    if (api_filter_raid($Raid, $aFetchFull, $aFetchFree)) {
        array_push($Result, $Raid);
    }
    return $Result;
}
Esempio n. 5
0
function api_query_user($aParameter)
{
    $aUsers = getParamFrom($aParameter, 'users', '');
    $aGames = getParamFrom($aParameter, 'games', '');
    $aCurrent = getParamFrom($aParameter, 'current', false);
    $aUTF8 = getParamFrom($aParameter, 'utf8', false);
    // load gameconfigs
    $GameFiles = scandir(dirname(__FILE__) . '/../../themes/games');
    $Games = array();
    foreach ($GameFiles as $GameFileName) {
        if (substr($GameFileName, -4) === '.xml') {
            $Game = loadGame(substr($GameFileName, 0, -4));
            $Games[$Game['GameId']] = $Game;
        }
    }
    // Build query
    $Parameters = array();
    $Conditions = array();
    // Filter users
    if (!$aCurrent && $aUsers != '') {
        $Users = explode(',', $aUsers);
        foreach ($Users as &$UserId) {
            $UserId = intval($UserId);
        }
        if (count($Users) == 1) {
            array_push($Conditions, 'UserId=?');
            array_push($Parameters, $Users[0]);
        } else {
            array_push($Conditions, 'UserId IN (' . implode(',', $Users) . ')');
        }
    }
    if ($aCurrent) {
        $Session = Session::get();
        if ($Session === null) {
            return array();
        }
        // no user logged in
        array_push($Conditions, 'UserId=?');
        array_push($Parameters, $Session->getUserId());
    }
    // Filter games
    if ($aGames != '') {
        $Games = explode(',', $aGames);
        $GameOptions = array();
        foreach ($Games as $Game) {
            array_push($GameOptions, 'Game=?');
            array_push($Parameters, $Game);
        }
        array_push($Conditions, $GameOptions);
    }
    // Build where clause
    $WhereString = '';
    if (count($Conditions) > 0) {
        foreach ($Conditions as &$Part) {
            if (is_array($Part)) {
                $Part = '(' . implode(' OR ', $Part) . ')';
            }
        }
        $WhereString = 'WHERE ' . implode(' AND ', $Conditions) . ' ';
    }
    // Run query
    $Connector = Connector::getInstance();
    $UserQuery = $Connector->prepare('SELECT `' . RP_TABLE_PREFIX . 'User`.UserId AS _UserId, `' . RP_TABLE_PREFIX . 'Character`.* FROM `' . RP_TABLE_PREFIX . 'User` ' . 'LEFT JOIN `' . RP_TABLE_PREFIX . 'Character` USING(UserId) ' . $WhereString . 'ORDER BY UserId,Name,Game');
    foreach ($Parameters as $Index => $Value) {
        //Out::getInstance()->pushValue('query', $Value);
        if (is_numeric($Value)) {
            $UserQuery->bindValue($Index + 1, $Value, PDO::PARAM_INT);
        } else {
            $UserQuery->bindValue($Index + 1, $Value, PDO::PARAM_STR);
        }
    }
    // Resolve result
    $Result = array();
    $LastUserId = 0;
    $User = array();
    $UserQuery->loop(function ($UserRow) use(&$LastUserId, &$Result, &$User, &$Games, $aUTF8) {
        if ($LastUserId != $UserRow['_UserId']) {
            if (count($User) > 0) {
                array_push($Result, $User);
            }
            $LastUserId = $UserRow['_UserId'];
            $User = array('Id' => $LastUserId, 'Characters' => array());
        }
        if ($UserRow['CharacterId'] != null) {
            $Game = $Games[$UserRow['Game']];
            $Classes = explode(':', $UserRow['Class']);
            $Roles = array();
            if ($Game['ClassMode'] == 'single') {
                // Single class mode -> Roles are in database
                array_push($Roles, $UserRow['Role1']);
                if ($UserRow['Role1'] != $UserRow['Role2']) {
                    array_push($Roles, $UserRow['Role2']);
                }
            } else {
                // Multi class mode -> Roles are attached to class
                foreach ($Classes as $ClassId) {
                    foreach ($Game['Classes'][$ClassId]['roles'] as $RoleId) {
                        if (!in_array($RoleId, $Roles)) {
                            array_push($Roles, $RoleId);
                        }
                    }
                }
            }
            array_push($User['Characters'], array('Name' => $aUTF8 ? xmlToUTF8($UserRow['Name']) : $UserRow['Name'], 'Game' => $UserRow['Game'], 'IsMainChar' => $UserRow['Mainchar'] == 'true', 'Classes' => $Classes, 'Roles' => $Roles));
        }
    });
    if (count($User) > 0) {
        array_push($Result, $User);
    }
    return $Result;
}
Esempio n. 6
0
function api_query_statistic($aParameter)
{
    $aStart = getParamFrom($aParameter, 'start', 0);
    $aEnd = getParamFrom($aParameter, 'end', time());
    $aRaids = getParamFrom($aParameter, 'raids', '');
    $aUsers = getParamFrom($aParameter, 'users', '');
    $aGames = getParamFrom($aParameter, 'games', '');
    $aUTF8 = getParamFrom($aParameter, 'utf8', false);
    // Build query
    $Conditions = array('`' . RP_TABLE_PREFIX . 'Character`.Mainchar = true', '`' . RP_TABLE_PREFIX . 'Character`.Game = `' . RP_TABLE_PREFIX . 'Location`.Game', '`' . RP_TABLE_PREFIX . 'Raid`.Start > `' . RP_TABLE_PREFIX . 'User`.Created', '`' . RP_TABLE_PREFIX . 'Raid`.Start > FROM_UNIXTIME(:Start)', '`' . RP_TABLE_PREFIX . 'Raid`.Start < FROM_UNIXTIME(:End)');
    $Parameters = array("Start" => $aStart, "End" => $aEnd);
    $GamesCondition = '';
    $GamesParameter = array();
    // Filter users
    if ($aUsers != '') {
        $Users = explode(',', $aUsers);
        foreach ($Users as &$UserId) {
            $UserId = intval($UserId);
        }
        if (count($Users) == 1) {
            array_push($Conditions, '`' . RP_TABLE_PREFIX . 'User`.UserId=:UserId');
            $Parameters["UserId"] = $Users[0];
        } else {
            array_push($Conditions, '`' . RP_TABLE_PREFIX . 'User`.UserId IN (' . implode(',', $Users) . ')');
        }
    }
    // Filter raids
    if ($aRaids != '') {
        $Raids = explode(',', $aRaids);
        foreach ($Raids as &$RaidId) {
            $RaidId = intval($RaidId);
        }
        if (count($Raids) == 1) {
            array_push($Conditions, '`' . RP_TABLE_PREFIX . 'raid`.RaidId=:RaidId');
            $Parameters["RaidId"] = $Raids[0];
        } else {
            array_push($Conditions, '`' . RP_TABLE_PREFIX . 'raid`.RaidId IN (' . implode(',', $Raids) . ')');
        }
    }
    // Filter games
    if ($aGames != '') {
        $Games = explode(',', $aGames);
        $GameByLoc = array();
        $GameIdx = 0;
        foreach ($Games as $Game) {
            array_push($GameByLoc, '`' . RP_TABLE_PREFIX . 'Location`.Game=:Game' . $GameIdx);
            $Parameters["Game" . $GameIdx] = $Game;
            $GamesParameter["Game" . $GameIdx] = $Game;
            ++$GameIdx;
        }
        $GamesCondition = implode(' OR ', $GameByLoc);
        array_push($Conditions, $GameByLoc);
    }
    // Build where clause
    $WhereString = '';
    if (count($Conditions) > 0) {
        foreach ($Conditions as &$Part) {
            if (is_array($Part)) {
                $Part = '(' . implode(' OR ', $Part) . ')';
            }
        }
        $WhereString = ' WHERE ' . implode(' AND ', $Conditions) . ' ';
    }
    // Query attendances
    $QueryString = 'SELECT ' . '`' . RP_TABLE_PREFIX . 'User`.UserId, ' . '`' . RP_TABLE_PREFIX . 'Character`.Name, ' . '`' . RP_TABLE_PREFIX . 'Attendance`.`Status`, ' . '`' . RP_TABLE_PREFIX . 'Attendance`.Role, ' . 'UNIX_TIMESTAMP(`' . RP_TABLE_PREFIX . 'User`.Created) AS CreatedUTC, ' . 'COUNT(`' . RP_TABLE_PREFIX . 'Raid`.RaidId) AS Count ' . 'FROM `' . RP_TABLE_PREFIX . 'User` ' . 'LEFT JOIN `' . RP_TABLE_PREFIX . 'Attendance` USING(UserId) ' . 'LEFT JOIN `' . RP_TABLE_PREFIX . 'Raid` USING(RaidId) ' . 'LEFT JOIN `' . RP_TABLE_PREFIX . 'Location` USING(LocationId) ' . 'LEFT JOIN `' . RP_TABLE_PREFIX . 'Character` ON `' . RP_TABLE_PREFIX . 'User`.UserId = `' . RP_TABLE_PREFIX . 'Character`.UserId ' . $WhereString . 'GROUP BY `' . RP_TABLE_PREFIX . 'User`.UserId, `' . RP_TABLE_PREFIX . 'Attendance`.`Status`, `' . RP_TABLE_PREFIX . 'Attendance`.Role ';
    $Connector = Connector::getInstance();
    $AttendanceQuery = $Connector->prepare($QueryString);
    foreach ($Parameters as $IndexName => $Value) {
        if (is_numeric($Value)) {
            $AttendanceQuery->bindValue(':' . $IndexName, $Value, PDO::PARAM_INT);
        } else {
            $AttendanceQuery->bindValue(':' . $IndexName, $Value, PDO::PARAM_STR);
        }
    }
    $UserId = 0;
    $NumRaidsRemain = 0;
    $MainCharName = '';
    $StateCounts = array('undecided' => 0, 'available' => 0, 'unavailable' => 0, 'ok' => 0);
    $Attendances = array();
    $Roles = array();
    $AttendanceQuery->loop(function ($Data) use($Connector, &$UserId, &$NumRaidsRemain, &$MainCharName, &$StateCounts, &$Attendances, &$Roles, $aUTF8, &$GamesCondition, &$GamesParameter, $aStart, $aEnd) {
        if ($UserId != $Data['UserId']) {
            // User changed, store cache
            if ($UserId != 0) {
                $AttendanceData = array('Id' => $UserId, 'MainChar' => $aUTF8 ? xmlToUTF8($MainCharName) : $MainCharName, 'SetToRaid' => $StateCounts['ok'], 'Available' => $StateCounts['available'], 'Absent' => $StateCounts['unavailable'], 'Undecided' => $StateCounts['undecided'] + $NumRaidsRemain, 'Roles' => $Roles);
                array_push($Attendances, $AttendanceData);
            }
            // Clear cache
            $StateCounts['ok'] = 0;
            $StateCounts['available'] = 0;
            $StateCounts['unavailable'] = 0;
            $StateCounts['undecided'] = 0;
            $NumRaidsRemain = 0;
            $Roles = array();
            $UserId = $Data['UserId'];
            $MainCharName = $Data['Name'];
            // Fetch number of attendable raids
            $RaidQueryString = 'SELECT ' . 'COUNT(RaidId) AS `NumberOfRaids` ' . 'FROM `' . RP_TABLE_PREFIX . 'Raid` ' . 'LEFT JOIN `' . RP_TABLE_PREFIX . 'Location` USING(LocationId) ' . 'WHERE `' . RP_TABLE_PREFIX . 'Raid`.Start > FROM_UNIXTIME(:Created) ' . 'AND `' . RP_TABLE_PREFIX . 'Raid`.Start > FROM_UNIXTIME(:Start) ' . 'AND `' . RP_TABLE_PREFIX . 'Raid`.Start < FROM_UNIXTIME(:End) ' . ($GamesCondition == '' ? '' : 'AND (' . $GamesCondition . ')');
            $Raids = $Connector->prepare($RaidQueryString);
            $Raids->bindValue(':Start', $aStart, PDO::PARAM_INT);
            $Raids->bindValue(':End', $aEnd, PDO::PARAM_INT);
            $Raids->bindValue(':Created', $Data['CreatedUTC'], PDO::PARAM_INT);
            foreach ($GamesParameter as $IndexName => $Value) {
                if (is_numeric($Value)) {
                    $Raids->bindValue(':' . $IndexName, $Value, PDO::PARAM_INT);
                } else {
                    $Raids->bindValue(':' . $IndexName, $Value, PDO::PARAM_STR);
                }
            }
            $RaidCountData = $Raids->fetchFirst();
            $NumRaidsRemain = $RaidCountData == null ? 0 : $RaidCountData['NumberOfRaids'];
        }
        // Same user / first entry, add data to cache
        if ($Data['Status'] == null) {
            return true;
        }
        // ### continue, invalid data ###
        $StateCounts[$Data['Status']] += $Data['Count'];
        $NumRaidsRemain -= $Data['Count'];
        if ($Data['Role'] == null || $Data['Status'] != 'ok') {
            return true;
        }
        // ### continue, no role set or absent ###
        if (!isset($Roles[$Data['Role']])) {
            $Roles[$Data['Role']] = $Data['Count'];
        } else {
            $Roles[$Data['Role']] += $Data['Count'];
        }
    });
    // Push last user
    if ($UserId != 0) {
        $AttendanceData = array('Id' => $UserId, 'MainChar' => $aUTF8 ? xmlToUTF8($MainCharName) : $MainCharName, 'SetToRaid' => $StateCounts['ok'], 'Available' => $StateCounts['available'], 'Absent' => $StateCounts['unavailable'], 'Undecided' => $StateCounts['undecided'] + $NumRaidsRemain, 'Roles' => $Roles);
        array_push($Attendances, $AttendanceData);
    }
    return $Attendances;
}