72 votes

PHP file_get_contents très lent lorsqu'il utilise l'url complète

Je travaille avec un script (que je n'ai pas créé à l'origine) qui génère un fichier pdf à partir d'une page HTML. Le problème est qu'il prend maintenant un temps très long, comme 1-2 minutes, à traiter. Il est supposé que cela fonctionnait bien à l'origine, mais que cela a ralenti au cours des deux dernières semaines.

Le script appelle file_get_contents sur un script php, qui sort ensuite le résultat dans un fichier HTML sur le serveur, et exécute l'application de génération de pdf sur ce fichier.

Je semble avoir réduit le problème au file_get_contents sur une url complète, plutôt que sur un chemin local.

Quand j'utilise

$content = file_get_contents('test.txt');

il traite presque instantanément. Cependant, si j'utilise l'url complète

$content = file_get_contents('http://example.com/test.txt');

le traitement prend entre 30 et 90 secondes.

Ce n'est pas limité à notre serveur, il est lent lors de l'accès à toute url externe, telle que http://www.google.com . Je crois que le script appelle l'url complet parce qu'il y a des variables de chaîne de requête qui sont nécessaires et qui ne fonctionnent pas si vous appelez le fichier localement.

J'ai aussi essayé fopen , readfile et curl et ils étaient tous aussi lents. Avez-vous des idées sur la façon de résoudre ce problème ?

1voto

Marc B Points 195501

Pouvez-vous essayer de récupérer cette URL, sur le serveur, à partir de la ligne de commande ? curl ou wget me viennent à l'esprit. Si ceux-ci récupèrent l'URL à une vitesse normale, alors il ne s'agit pas d'un problème de réseau et très probablement d'un problème dans la configuration d'apache/php.

1 votes

Lorsque j'essaie wget à partir de la ligne de commande, c'est également très lent. Il s'arrête à l'étape de résolution.... Un problème de DNS sur le serveur ?

0 votes

Ça pourrait l'être. Essayez d'utiliser 'host' ou 'nslookup' (ce qui est disponible) et essayez de résoudre différents noms d'hôtes à partir du système.

0voto

Elyor Points 3049

J'ai un grand nombre de données transmises par l'API. file_get_contents pour lire les données, mais cela a pris environ 60 secondes . Cependant, en utilisant la solution de KrisWebDev, il a fallu compter environ 1,5 million d'euros. 25 secondes .

$context = stream_context_create(array('https' => array('header'=>'Connection: close\r\n')));
file_get_contents($url,false,$context);

0voto

Mike Q Points 461

Ce que je considère également avec Curl, c'est que vous pouvez "filtrer" les requêtes. Cela m'a énormément aidé car je n'ai pas accès à une version de PHP qui permette l'enfilage pour le moment.

Par exemple, j'obtenais 7 images d'un serveur distant en utilisant file_get_contents et cela prenait 2 à 5 secondes par requête. Ce seul processus ajoutait environ 30 secondes au processus, pendant que l'utilisateur attendait que le PDF soit généré.

Cela a littéralement réduit le temps à environ une image. Autre exemple, j'ai vérifié 36 urls dans le temps qu'il fallait auparavant pour en faire une. Je pense que vous avez compris :-)

    $timeout = 30;
    $retTxfr = 1;
    $user = '';
    $pass = '';

    $master = curl_multi_init();
    $node_count = count($curlList);
    $keys = array("url");

    for ($i = 0; $i < $node_count; $i++) {
        foreach ($keys as $key) {
            if (empty($curlList[$i][$key])) continue;
            $ch[$i][$key] = curl_init($curlList[$i][$key]);
            curl_setopt($ch[$i][$key], CURLOPT_TIMEOUT, $timeout); // -- timeout after X seconds
            curl_setopt($ch[$i][$key], CURLOPT_RETURNTRANSFER, $retTxfr);
            curl_setopt($ch[$i][$key], CURLOPT_HTTPAUTH, CURLAUTH_ANY);
            curl_setopt($ch[$i][$key], CURLOPT_USERPWD, "{$user}:{$pass}");
            curl_setopt($ch[$i][$key], CURLOPT_RETURNTRANSFER, true);
            curl_multi_add_handle($master, $ch[$i][$key]);
        }
    }

    // -- get all requests at once, finish when done or timeout met --
    do {  curl_multi_exec($master, $running);  }
    while ($running > 0);

Vérifiez ensuite les résultats :

            if ((int)curl_getinfo($ch[$i][$key], CURLINFO_HTTP_CODE) > 399 || empty($results[$i][$key])) {
                unset($results[$i][$key]);
            } else {
                $results[$i]["options"] = $curlList[$i]["options"];
            }
            curl_multi_remove_handle($master, $ch[$i][$key]);
            curl_close($ch[$i][$key]);

puis fermer le fichier :

    curl_multi_close($master);

0voto

ElChupacabra Points 543

Je sais que c'est une vieille question mais je l'ai trouvée aujourd'hui et les réponses n'ont pas fonctionné pour moi. Je n'ai vu personne dire que le nombre maximal de connexions par IP peut être fixé à 1. De cette façon, vous faites une demande d'API et l'API fait une autre demande parce que vous utilisez l'url complète. C'est pourquoi le chargement direct depuis le disque fonctionne. Pour moi, cela a réglé un problème :

if (strpos($file->url, env('APP_URL')) === 0) {
    $url = substr($file->url, strlen(env('APP_URL')));
} else {
    $url = $file->url;
}
return file_get_contents($url);

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X