简体   繁体   中英

PHP CURL Request in For-Loop really slow

I'm working on a guild homepage with a page which displays our Guild Roster. The data gets extracted from the blizzard API using Oauth and everything works so far. The problem is that the roster page takes at least 10 seconds to load. Using Postman I get the results usually in 200ms. I tested around and figured that the requests in the for-loop slow it down by a lot. Since this is my first time working with curl, my code is a bit messy. Do you have any tips how to improve the requests in the for-loop? Thanks in advance

<?php


$curl_handle = curl_init();

curl_setopt($curl_handle, CURLOPT_URL, "https://eu.battle.net/oauth/token");
curl_setopt($curl_handle, CURLOPT_POSTFIELDS, ['grant_type' => 'client_credentials']);
curl_setopt($curl_handle, CURLOPT_USERPWD, $apikey . ':' . $apisecret);
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_setopt($curl_handle, CURLOPT_USERAGENT, 'Mozilla/5.001 (windows; U; NT4.0; en-US; rv:1.0) Gecko/25250101');
curl_setopt($curl_handle, CURLOPT_HTTPHEADER, ['Content-Type: multipart/form-data']);


$response = curl_exec($curl_handle);
$access_token = json_decode($response)->access_token;


curl_reset($curl_handle);

curl_setopt($curl_handle, CURLOPT_URL, "https://eu.api.blizzard.com/data/wow/guild/malfurion/war-hounds/roster?namespace=profile-eu");
curl_setopt($curl_handle, CURLOPT_HTTPHEADER, ['Content-Type: multipart/form-data','Authorization: Bearer ' . $access_token]);
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_setopt($curl_handle, CURLOPT_USERAGENT, 'Mozilla/5.001 (windows; U; NT4.0; en-US; rv:1.0) Gecko/25250101');


$guildrequest = curl_exec($curl_handle);
$guildname = json_decode($guildrequest, true);
$name1 = $guildname['members'];

curl_reset($curl_handle);
curl_setopt($curl_handle, CURLOPT_HTTPHEADER, ['Content-Type: multipart/form-data','Authorization: Bearer ' . $access_token]);
curl_setopt($curl_handle, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl_handle, CURLOPT_IPRESOLVE, CURL_IPRESOLVE_V4);
curl_setopt($curl_handle, CURLOPT_USERAGENT, 'Mozilla/5.001 (windows; U; NT4.0; en-US; rv:1.0) Gecko/25250101');


echo "<table style=\"background-color:#595959;border:2px solid black\">";
echo "<tr><th>Roster</th><th>Name</th><th>Klasse</th></tr>";
echo "<style> tr:nth-child(even) {background-color: #4a4a4a;} table{border-collapse: collapse;} 
</style>";

for($i=0; $i<count($name1);$i++)
{
//player-class general json
curl_setopt($curl_handle, CURLOPT_URL, $name1[$i][character][playable_class][key][href]);
$playerClass = curl_exec($curl_handle);
$playerClassName = json_decode($playerClass, true);

//player-class media
curl_setopt($curl_handle, CURLOPT_URL, $playerClassName[media][key][href]);
$icon = curl_exec($curl_handle);
$playerClassIcon = json_decode($icon, true);
$urlPrep = $playerClassIcon[assets][0][value];
$url = str_replace( 'https://', 'http://', $urlPrep);
 
//player general json
curl_setopt($curl_handle, CURLOPT_URL,$name1[$i][character][key][href]);
$character = curl_exec($curl_handle);
$characterJSON = json_decode($character, true);
 
//player media
$urlMedia = $characterJSON[media][href];
curl_setopt($curl_handle, CURLOPT_URL,$urlMedia);
$charactermedia = curl_exec($curl_handle);
$charactermediaJSON = json_decode($charactermedia,true);
$urlPrep2 = $charactermediaJSON[assets][0][value];

if($urlPrep2 == null){

    $urlPrep2 = $charactermediaJSON[avatar_url];
}
$url2 = str_replace( 'https://', 'http://', $urlPrep2);

$color = black;

echo "<tr><td><img src=\"" .$url2. "\" alt=\"".$name1[$i][character][name]. "\"></td><td style=\"font-weight:bold;color:".$color."\"><a style=\"font-weight:bold;color:".$color."\" href=\"https://worldofwarcraft.com/de-de/character/eu/".$name1[$i][character][realm][slug]."/".$name1[$i][character][name]."\">" .$name1[$i][character][name]. "</a></td><td><img src=\"" .$url. "\" alt=\"" .$playerClassName[name][de_DE]. "\" ></td></tr>";

}
?>

First, I'd recommend you obscure your API keys, on principle, assuming you've shown the real ones.

As for your question, without going through the rest of your code and trying to make it more efficient - or looking into the question of whether some other API request mode might work as well or better - I'd suggest you considering saving the returned values as re-usable transients that will in turn be refreshed only when necessary. The latter objective can be handled in a variety of different ways, but the main result will be that the set of requests won't need to be made every time the page output has to be re-loaded.

https://developer.wordpress.org/apis/handbook/transients/

don't ever do

curl_setopt($curl_handle, CURLOPT_POSTFIELDS, [
    'grant_type' => 'client_credentials'
]);
curl_setopt($curl_handle, CURLOPT_HTTPHEADER, [
    'Content-Type: multipart/form-data'
]);

you risk ruining the request, the request is supposed to look like:

Content-Length: 163
Content-Type: multipart/form-data; boundary=------------------------becb5cf73f034d20

--------------------------becb5cf73f034d20
Content-Disposition: form-data; name="grant_type"

client_credentials
--------------------------becb5cf73f034d20--

when you attempt to overwrite the multipart-header that curl generates automatically, you risk removing the boundary from the header, making the request unparsable, so let curl generate the multipart header automatically, don't override it.

optimization.. the first request to fetch an oAuth token can be replaced by a minutely cronjob which every minute 24/7 generate a fresh token and stores it in a database. fetching the token from your own database should be much faster than generating a new one from Blizzard, so that would speed things up: always generate new tokens with cronjobs and cache it.

but since the request you send is not dynamic at all, it does not appear to depend on any $_GET or $_POST requests, or anything like that, having a cronjob generating a fresh html page every minute, and just serving your newest version of the html file would be much faster. the very fastest a cronjob can run is every 60 seconds, if that is too slow for you (eg you need every 10 seconds, or 30), then consider using a daemon, or you can use some cronjob-hacks, like every minute you have cronjob php generateHtml.php , and you have sleep 30 && php generateHtml.php - this hack wil allow you to run cronjobs every 30 seconds instead of the normal 1 minute limit; you can do the same with sleep 10 && + sleep 20 && etc, to have the cronjob even run every 10 seconds.

using a cronjob will make your actual pageloads take milliseconds, instead of the 10+ sec you're suffering with now :)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM