2009-06-10 6 views
2

Ce premier script est appelé plusieurs fois pour chaque utilisateur via une requête AJAX. Il appelle un autre script sur un serveur différent pour obtenir la dernière ligne d'un fichier texte. Il fonctionne très bien, mais je pense qu'il ya beaucoup de place à l'amélioration, mais je ne suis pas un très bon codeur PHP, donc j'espère avec l'aide de la communauté, je peux optimiser cette vitesse et l'efficacité:Comment puis-je optimiser ce script PHP simple?

AJAX POST demande faite à ce script

<?php session_start(); 
$fileName = $_POST['textFile']; 
$result = file_get_contents($_SESSION['serverURL']."fileReader.php?textFile=$fileName"); 
echo $result; 
?> 

Il fait une requête GET à ce script externe qui lit un fichier texte

<?php 
$fileName = $_GET['textFile']; 
if (file_exists('text/'.$fileName.'.txt')) { 
    $lines = file('text/'.$fileName.'.txt'); 
    echo $lines[sizeof($lines)-1]; 
} 
else{ 
    echo 0; 
} 
?> 

Je vous serais reconnaissant toute h elp. Je pense qu'il y a plus d'améliorations qui peuvent être faites dans le premier script. Cela fait un appel de fonction cher (file_get_contents), enfin je pense que c'est cher!

+0

Je sais qu'il n'y a rien de mal à cela parce que cela fonctionne, mais j'essaie juste de l'améliorer car ce script sera appelé 10000 fois. :) – Abs

Répondre

1

Ce script devrait limiter les emplacements et les types de fichiers qu'il va revenir.

Pensez quelqu'un essayer ceci:

http://www.yoursite.com/yourscript.php?textFile=../../../etc/passwd (ou quelque chose de similaire)

Essayez de savoir où les retards se produisent .. ne la demande HTTP prend de temps, ou est le fichier si grand que sa lecture prend longue.

Si la requête est lente, essayez de mettre en cache les résultats localement. Si le fichier est volumineux, vous pouvez configurer un travail cron qui extrait la dernière ligne du fichier à intervalles réguliers (ou à chaque modification) et l'enregistrer dans un fichier auquel votre autre script peut accéder directement.

0

Si les fichiers ne changent pas, vous devez mettre en cache la dernière ligne.

Si les fichiers changent et que vous contrôlez la façon dont ils sont produits, cela peut être ou ne pas être une amélioration pour inverser les lignes de commande, selon la fréquence de lecture d'une ligne sur sa durée de vie.

Edit:

Votre serveur peut comprendre ce qu'il veut écrire dans son journal, le mettre dans memcache, puis l'écrire dans le journal. La requête pour la dernière ligne pourrait être remplie à partir de memcache au lieu de lire le fichier.

+0

Oui, les fichiers changent tout le temps. J'aime la dernière idée, en inversant l'ordre des lignes pour ne récupérer que la première ligne. J'ai besoin de chaque petit peu de gains de performance que je peux obtenir! – Abs

1

readfile est votre ami ici il lit un fichier sur le disque et le transmet au client.

scénario

1:

<?php 
    session_start(); 
    // added basic argument filtering 
    $fileName = preg_replace('/[^A-Za-z0-9_]/', '', $_POST['textFile']); 

    $fileName = $_SESSION['serverURL'].'text/'.$fileName.'.txt'; 
    if (file_exists($fileName)) { 

     // script 2 could be pasted here 

     //for the entire file 
     //readfile($fileName); 

     //for just the last line 
     $lines = file($fileName); 
     echo $lines[count($lines)-1]; 


     exit(0); 
    } 

    echo 0; 
?> 

Ce script pourrait encore être améliorée en ajoutant la mise en cache à elle. Mais c'est plus compliqué. Le très la mise en cache de base pourrait être.

scénario

2:

<?php 

    $lastModifiedTimeStamp filemtime($fileName); 

    if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE'])) { 
     $browserCachedCopyTimestamp = strtotime(preg_replace('/;.*$/', '', $_SERVER['HTTP_IF_MODIFIED_SINCE'])); 
     if ($browserCachedCopyTimestamp >= $lastModifiedTimeStamp) { 
      header("HTTP/1.0 304 Not Modified"); 
      exit(0); 
     } 
    } 

    header('Content-Length: '.filesize($fileName)); 
    header('Expires: '.gmdate('D, d M Y H:i:s \G\M\T', time() + 604800)); // (3600 * 24 * 7) 
    header('Last-Modified: '.date('D, d M Y H:i:s \G\M\T', $lastModifiedTimeStamp)); 
?> 
+0

Diriez-vous que je devrais l'utiliser si le client n'a besoin que de la dernière ligne? – Abs

+0

'script 1' remplace vos 2 scripts. readfile() lit le fichier entier et l'envoie au navigateur. si vous n'êtes pas sûr, oubliez le 'script 2' – Jacco

+0

Est-ce que file_exists fonctionne sur des fichiers distants (URL)? – Abs

0

Tout d'abord: avez-vous vraiment besoin d'optimiser cela? Est-ce la partie la plus lente de votre cas d'utilisation?Avez-vous utilisé xdebug pour le vérifier? Si vous avez déjà fait cela, lisez ce qui suit:

Vous ne pouvez pas réellement optimiser le premier script: Si vous avez besoin d'une requête http, vous avez besoin d'une requête http. Ignorer la requête http pourrait cependant être un gain de performance, si cela est possible (c'est-à-dire si le premier script peut accéder aux mêmes fichiers sur lesquels le deuxième script fonctionnerait). Comme pour le deuxième script: Lire le fichier entier en mémoire ressemble à une surcharge, mais c'est négligeable, si les fichiers sont petits. Le code semble très lisible, je le laisserais tel quel dans ce cas.

Si vos fichiers sont grandes, cependant, vous voudrez peut-être utiliser fopen() et ses amis fseek() et fread()

# Do not forget to sanitize the file name here! 
# An attacker could demand the last line of your password 
# file or similar! ($fileName = '../../passwords.txt') 
$filePointer = fopen($fileName, 'r'); 
$i = 1; 
$chunkSize = 200; 
# Read 200 byte chunks from the file and check if the chunk 
# contains a newline 
do { 
    fseek($filePointer, -($i * $chunkSize), SEEK_END); 
    $line = fread($filePointer, $i++ * $chunkSize); 
} while (($pos = strrpos($line, "\n")) === false); 
return substr($line, $pos + 1); 
+0

Merci pour votre réponse perspicace. Je n'ai pas utilisé ça (xdebug) auparavant mais je le regarde maintenant. Les fichiers texte que je lis ne sont pas plus de 20 lignes et les lignes sont d'environ 5/6 mots. – Abs

+0

Je ne toucherais pas le code, alors. L'overhead de l'interprétation de la boucle pourrait même être supérieur au gain avec les fichiers de cette taille :) – soulmerge

+0

Ah vous avez raison, merci! :) – Abs

0

La source la plus probable de retard est que la requête HTTP croisée serveur. Si les fichiers sont petits, le coût de fopen/fread/fclose n'est rien comparé à l'ensemble de la requête HTTP.

(Il n'y a pas longtemps je HTTP pour récupérer des images pour générer dynamiquement des menus à base d'images. Remplacement de la requête HTTP par une lecture de fichier local réduit le délai de quelques secondes à dixièmes de seconde.)

Je suppose que la solution évidente d'accéder directement au système de fichiers du serveur de fichiers est hors de question. Si non, alors c'est l'option la meilleure et la plus simple.

Sinon, vous pouvez utiliser la mise en cache. Au lieu d'obtenir le fichier entier, il suffit d'émettre une requête HEAD et de comparer l'horodatage à une copie locale. En outre, si vous effectuez une mise à jour ajax pour beaucoup de clients basés sur les mêmes fichiers, vous pouvez envisager d'utiliser comet (meteor, par exemple). Il est utilisé pour des choses comme les chats, où un seul changement doit être diffusé à plusieurs clients.