<?php
$year = "2025";
$stage = "01";
$classifications = ['ITG', 'IPG', 'IMG', 'IJG', 'ETG'];
$results = [];
$teamPositions = [];

$mh = curl_multi_init();

// Multi-curl request for team data and stage data
$teamDataUrl = "https://api.cycling.matsport.com/competitions/{$year}_LUX";
$ch_team = curl_init($teamDataUrl);
curl_setopt($ch_team, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $ch_team);

$apiUrl = "https://api.cycling.matsport.com/stages/{$year}_LUX_STAGE_{$stage}";
$ch_stage = curl_init($apiUrl);
curl_setopt($ch_stage, CURLOPT_RETURNTRANSFER, true);
curl_multi_add_handle($mh, $ch_stage);

// Execute all requests in parallel
$running = null;
do {
    curl_multi_exec($mh, $running);
} while ($running);

// Close handles
curl_multi_remove_handle($mh, $ch_team);
curl_multi_remove_handle($mh, $ch_stage);
curl_multi_close($mh);

// Process team data
$teamData = json_decode(curl_multi_getcontent($ch_team), true);
if (isset($teamData['teams']) && is_array($teamData['teams'])) {
    $teamPositions = array_map(function ($index, $team) {
        return [
            'TeamName' => $team['name'],
            'Position' => '#' . ($index + 1)
        ];
    }, array_keys($teamData['teams']), $teamData['teams']);
}

// Process stage data
$data = json_decode(curl_multi_getcontent($ch_stage), true);

foreach ($classifications as $classification) {
    $riderData = [];

    foreach ($teamData['teams'] as $team) {
        foreach ($team['riders'] as $rider) {
            $bibNumber = $rider['bib'];
            $riderName = $rider['firstname'] . ' ' . $rider['lastname'];
            $nationality = $rider['nationality'];
            $riderImage = $rider['image'];
            $teamName = $team['name'];

            $riderData[$bibNumber] = [
                'BibNumber' => "#$bibNumber",
                'Rank' => '',
                'RiderName' => $riderName,
                'TeamName' => $teamName,
                'RiderImage' => $riderImage,
                'Nationality' => $nationality,
                'Capital' => '',
                'Bonus' => '',
                'Gap' => '',
                'Penalty' => '',
                'Status' => ''
            ];
        }
    }

    if (isset($data['rankingTypes']) && is_array($data['rankingTypes'])) {
        foreach ($data['rankingTypes'] as $rankingType) {
            if ($rankingType['type'] === $classification && isset($rankingType['rankings']) && is_array($rankingType['rankings'])) {
                $ranking = $rankingType['rankings'][0] ?? null;

               if ($ranking) {
                    $bibNumber = $ranking['bib'];

                    if (isset($riderData[$bibNumber]) || $classification === 'ETG') {
                        if ($classification !== 'ETG'){$riderInfo = $riderData[$bibNumber];}
                        $position = $ranking['position'] === -1 ? 'DNF' : $ranking['position'];
                      
                      if ($classification === 'ETG' && isset($teamPositions[$bibNumber-1])) {
                            $teamInfo = $teamPositions[$bibNumber-1];
                            $riderInfo['RiderName'] = $teamInfo['TeamName'];
                        $riderInfo['TeamName'] = '';
                        }
                      
                      global $results;

                        $results[] = [
                            'Classification' => $classification,
                            'BibNumber' => $bibNumber,
                            'RiderName' => $riderInfo['RiderName'],
                            'Capital' => $ranking['capital'] ?? '-',
                            'TeamName' => $riderInfo['TeamName']
                        ];
                    } else {
                        echo "<script>console.log('No rider information found for bibNumber: $bibNumber');</script>";
                    }
                }
            }
        }
    }
}

function getValueOrAwaited($value) {
    return !empty($value) ? $value : 'Data awaited';
}

function getITGBib() {
    global $results;
    return getValueOrAwaited($results[0]['BibNumber']);
}

function getITGRider() {
    global $results;
    return getValueOrAwaited($results[0]['RiderName']);
}

function getITGCapital() {
    global $results;
    return getValueOrAwaited($results[0]['Capital']);
}

function getITGTeam() {
    global $results;
    return getValueOrAwaited($results[0]['TeamName']);
}

function getIPGBib() {
    global $results;
    return getValueOrAwaited($results[1]['BibNumber']);
}

function getIPGRider() {
    global $results;
    return getValueOrAwaited($results[1]['RiderName']);
}

function getIPGCapital() {
    global $results;
    return getValueOrAwaited($results[1]['Capital']);
}

function getIPGTeam() {
    global $results;
    return getValueOrAwaited($results[1]['TeamName']);
}

function getIMGBib() {
    global $results;
    return getValueOrAwaited($results[2]['BibNumber']);
}

function getIMGRider() {
    global $results;
    return getValueOrAwaited($results[2]['RiderName']);
}

function getIMGCapital() {
    global $results;
    return getValueOrAwaited($results[2]['Capital']);
}

function getIMGTeam() {
    global $results;
    return getValueOrAwaited($results[2]['TeamName']);
}

function getIJGBib() {
    global $results;
    return getValueOrAwaited($results[3]['BibNumber']);
}

function getIJGRider() {
    global $results;
    return getValueOrAwaited($results[3]['RiderName']);
}

function getIJGCapital() {
    global $results;
    return getValueOrAwaited($results[3]['Capital']);
}

function getIJGTeam() {
    global $results;
    return getValueOrAwaited($results[3]['TeamName']);
}

function getETGRider() {
    global $results;
    return getValueOrAwaited($results[4]['RiderName']);
}

function getETGCapital() {
    global $results;
    return getValueOrAwaited($results[4]['Capital']);
}
?>
Luxembourg Logo
UCI Pro Series Logo
ALPECIN-PREMIER TECH

#11 Mathieu VAN DER POEL

3:45:32
ALPECIN-PREMIER TECH

#11 Mathieu VAN DER POEL

20 pts
TEAM COLOQUICK

#144 Malte HELLERUP

13 pts
DECATHLON CMA CGM TEAM

#23 Pierre GAUTHERAT

3:45:36
Best Team

TEAM VISMA | LEASE A BIKE

11:17:16
SEE ALL THE RESULTS HERE
Results Data by Matsport
SUBSCRIBE TO NEWSLETTER
Keep updated with the latest news
Live Rankings for 2026
ALPECIN-PREMIER TECH

##11 Mathieu VAN DER POEL

3:45:32
ALPECIN-PREMIER TECH

##11 Mathieu VAN DER POEL

20 pts
TEAM COLOQUICK

##144 Malte HELLERUP

13 pts
DECATHLON CMA CGM TEAM

##23 Pierre GAUTHERAT

3:45:36
Best Team

TEAM VISMA | LEASE A BIKE

11:17:16
SEE ALL THE RESULTS HERE
Results Data by Matsport
SUBSCRIBE TO NEWSLETTER
Keep up to date with the latest news

Winner Stage 1 – Mathieu van der Poel

Photo by Serge Waldbillig

Škoda Tour de Luxembourg

MORE NEWS

SOCIAL MEDIA

Follow us on social media to get quick, live updates:
Skoda Tour de Luxembourg Favicon
Škoda Tour de Luxembourg

STAGES 2026

Discover the route

STAGE 1

Luxembourg – Knuedler > Luxembourg – Fëschmaart

MORE INFO

Stage-1

STAGE 2

Differdange/Niederkorn > Junglinster

MORE INFO

Stage-2

STAGE 3

Wiltz > Diekirch

MORE INFO

Stage-3

STAGE 4

Ettelbruck > Ettelbruck

MORE INFO

Stage-4

STAGE 5

Mersch > Luxembourg – Limpertsberg

MORE INFO

Stage-5

SEE ALL STAGES

PARTNERS

GALLERY

Check out the latest photos & videos from the Škoda Tour de Luxembourg
Tour de LuxembourgALL IMAGES & VIDEOS

Skoda Tour de Luxembourg 2024 Trailer

NEWSLETTER

Keep up to date with the latest new from the tour

NEWSLETTER

Keep up to date with the latest new from the tour
[dflip id="25818" ][/dflip]

NEWSLETTER

Keep up to date with the latest new from the tour
STAGEDATEROUTEDISTANCE
Stage 118/09Luxembourg Place Guillaume II > Luxembourg Kirchberg156,4 kms
Stage 219/09Junglinster > Schifflange155,0 kms
Stage 320/09Rosport > Diekrich201,3 kms
Stage 421/09Differdange > Differdange15,5 kms
Stage 522/09Mersch > Luxembourg Limpertsberg176,9 kms