Как я могу оптимизировать этот простой скрипт PHP? - PullRequest
2 голосов
/ 10 июня 2009

Этот первый скрипт вызывается несколько раз для каждого пользователя через запрос AJAX. Он вызывает другой скрипт на другом сервере, чтобы получить последнюю строку текстового файла. Это работает нормально, но я думаю, что есть много возможностей для улучшения, но я не очень хороший PHP-кодер, поэтому я надеюсь, что с помощью сообщества я могу оптимизировать это для скорости и эффективности:

AJAX POST Запрос к этому сценарию

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

Это делает запрос GET к этому внешнему сценарию, который читает текстовый файл

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

Буду признателен за любую помощь. Я думаю, что есть больше улучшений, которые можно сделать в первом сценарии. Это делает дорогой вызов функции (file_get_contents), ну, по крайней мере, я думаю, что это дорого!

Ответы [ 5 ]

1 голос
/ 10 июня 2009

readfile ваш друг здесь он читает файл на диске и передает его клиенту.

сценарий 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;
?>

Этот скрипт может быть улучшен путем добавления к нему кэширования. Но это сложнее. очень базовое кэширование может быть.

сценарий 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));
?>
1 голос
/ 10 июня 2009

Этот скрипт должен ограничивать расположение и типы файлов, которые он собирается возвращать.

Подумайте, кто-то пытается это:

http://www.yoursite.com/yourscript.php?textFile=../../../etc/passwd (или что-то подобное)

Попытайтесь выяснить, где происходят задержки ... занимает ли HTTP-запрос много времени или файл настолько велик, что чтение занимает много времени.

Если запрос медленный, попробуйте кэшировать результаты локально.

Если файл огромен, то вы можете настроить задание cron, которое будет извлекать последнюю строку файла через равные промежутки времени (или при каждом изменении), и сохранить его в файле, к которому ваш другой скрипт сможет напрямую обращаться.

0 голосов
/ 11 июня 2009

Наиболее вероятный источник задержки - это межсерверный HTTP-запрос. Если файлы небольшие, стоимость fopen / fread / fclose ничто по сравнению со всем HTTP-запросом.

(Недавно я использовал HTTP для извлечения изображений для динамического создания меню на основе изображений. Замена HTTP-запроса на чтение локального файла сократила задержку с секунд до десятых долей секунды.)

Я предполагаю, что об очевидном решении прямого доступа к файловой системе файлового сервера не может быть и речи. Если нет, то это лучший и самый простой вариант.

Если нет, вы можете использовать кеширование. Вместо того, чтобы получить весь файл, вы просто отправляете запрос HEAD и сравниваете метку времени с локальной копией.

Кроме того, если вы обновляете ajax многих клиентов на основе одних и тех же файлов, вы можете рассмотреть возможность использования кометы (например, meteor). Он используется для таких вещей, как чаты, где одно изменение должно быть передано нескольким клиентам.

0 голосов
/ 10 июня 2009

Перво-наперво: вам действительно нужно оптимизировать это? Это самая медленная часть в вашем случае использования? Вы использовали xdebug , чтобы проверить это? Если вы это сделали, читайте дальше:

Вы не можете реально оптимизировать первый скрипт с пользой: если вам нужен http-запрос, вам нужен http-запрос. Пропуск http-запроса может, тем не менее, повысить производительность, если это возможно (т. Е. Если первый скрипт может обращаться к тем же файлам, над которыми будет работать второй скрипт).

Что касается второго сценария: чтение всего файла в память выглядит как накладные расходы, но это незначительно, если файлы небольшие. Код выглядит очень читабельным, я бы оставил его как есть.

Однако, если ваши файлы большие, вы можете использовать fopen() и его друзей fseek() и 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 голосов
/ 10 июня 2009

Если файлы неизменны, вам следует кэшировать последнюю строку.

Если файлы меняются, и вы контролируете способ их создания, то может быть лучше, а может и не быть улучшение обратной записи строк заказа, в зависимости от того, как часто строка читается в течение срока ее жизни.

Edit:

Ваш сервер может выяснить, что он хочет записать в свой журнал, поместить его в memcache, а затем записать это в журнал. Запрос на последнюю строку может быть выполнен из memcache вместо чтения файла.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...