Оптимизировать PHP для обслуживания всех файлов (а не Apache) - PullRequest
0 голосов
/ 24 августа 2010

Мне нужно отправлять все запросы на любой веб-ресурс через PHP для проверки подлинности пользователя и не обслуживать какие-либо файлы напрямую через Apache.Вот мой .htaccess:

# All requests are routed to PHP (images, css, js, everything)
RewriteRule ^(.*)$ index.php?query=$1&%{QUERY_STRING} [L]

Затем я обрабатываю запрос, проверяю, что у пользователя есть доступ к ресурсу, а затем выводю любой файл, который не требует обработки, используя следующую функцию чтения PHP.Оказывается, это невероятно медленно по сравнению с тем, чтобы позволить Apache делать свое дело.

Кто-нибудь может порекомендовать способ помочь мне улучшить производительность?

static function read($path) {
    if(!File::exists($path)) {
        //echo 'File does not exist.';
        header("HTTP/1.0 404 Not Found");
        return;
    }

    $fileName = String::explode('/', $path);
    if(Arr::size($fileName) > 0) {
        $fileName = $fileName[Arr::size($fileName) - 1];
    }

    $size = File::size($path);
    $time = date('r', filemtime($path));

    $fm = @fopen($path, 'rb');
    if(!$fm) {
        header("HTTP/1.0 505 Internal server error");
        return;
    }

    $begin = 0;
    $end = $size;

    if(isset($_SERVER['HTTP_RANGE'])) {
        if(preg_match('/bytes=\h*(\d+)-(\d*)[\D.*]?/i', $_SERVER['HTTP_RANGE'], $matches)) {
            $begin = intval($matches[0]);
            if(!empty($matches[1]))
                $end = intval($matches[1]);
        }
    }

    if ($begin > 0 || $end < $size)
        header('HTTP/1.0 206 Partial Content');
    else
        header('HTTP/1.0 200 OK');

    // Find the mime type of the file
    $mimeType = 'application/octet-stream';
    //$finfo = @new finfo(FILEINFO_MIME);
    //print_r($finfo);
    //$fres = @$finfo->file($path);
    //if(is_string($fres) && !empty($fres)) {
       //$mimeType = $fres;
    //}

    // Handle CSS files
    if(String::endsWith('.css', $path)) {
        $mimeType = 'text/css';
    }

    header('Content-Type: '.$mimeType);
    //header('Cache-Control: public, must-revalidate, max-age=0');
    //header('Pragma: no-cache');
    header('Accept-Ranges: bytes');
    header('Content-Length:' . ($end - $begin));
    header("Content-Range: bytes $begin-$end/$size");
    header("Content-Disposition: inline; filename=$fileName");
    header("Content-Transfer-Encoding: binary\n");
    header("Last-Modified: $time");
    header('Connection: close');

    $cur = $begin;
    fseek($fm, $begin, 0);

    while(!feof($fm) && $cur < $end && (connection_status() == 0)) {
        print fread($fm, min(1024 * 16, $end - $cur));
        $cur += 1024 * 16;
    }
}

Ответы [ 9 ]

2 голосов
/ 24 августа 2010

Лучшее, что вы можете сделать, если используете PHP в качестве модуля Apache, это позвонить virtual.

В противном случае вам придется согласиться на readfile.

Другая возможность - полностью обойти PHP и использовать средства авторизации, аутентификации и контроля доступа Apache .Вы даже можете написать модуль Apache со своей собственной логикой аутентификации / авторизации, если это станет необходимым.

1 голос
/ 26 августа 2010

Прежде всего - ваш код может обслуживать только приложение / октет-поток и текст / css, и вы пытаетесь принудительно загрузить все.

Может кто-нибудь порекомендовать способ помочьмне улучшить производительность?

Да

  • gzip, как уже упоминалось в другом месте (но будьте внимательны к этому и кэшируйте сжатые версии на стороне сервера)

  • используйте mod_php или fastCGI вместо CGI

  • используйте кэш кода операции, такой как APC

  • , отправьте некоторую информацию о кешировании (но есливам нужна аутентификация для всего, включая заголовок Varies: Cookies)

  • использовать fpassthru вместо цикла while

  • использовать обратный прокси

  • выполнить аутентификацию на обратном прокси-сервере (просто с помощью URL-переписчика squid)

Существуют другие способы решения проблемы без перезаписи (например, обработчик 404, автоматическое добавление ко всем типам контента) - вы можете случайно получитьвнутренние проблемы рекурсии с mod_rewrite.

1 голос
/ 24 августа 2010

Добавить к ответу Джо Хопфгартнера ..

Да, буферизация вывода, вероятно, поможет, но вы должны проверить, что клиент принимает gzipped ответы, если это так, то вы должны также сжать буфер gzip, ответ будет намного меньше, а значит и быстрее. Проверьте документацию на сайте php.net о функциях ob_ * или о том, как сжать ваш контент в Google.

Кроме того,

Вы должны вызвать set_time_limit (0). Если запуск сценария занимает слишком много времени, он прервет передачу на полпути, и вы получите искаженный ответ.

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

1 голос
/ 24 августа 2010

Оказывается, это невероятно медленно по сравнению с тем, чтобы позволить Apache делать свое дело.

Я не думаю, что можно сделать многое для ускорения работы на этом низком уровне. К сожалению, нет простого способа заставить PHP выполнить проверку «залогинен», а затем передать фактическую подачу файла в Apache.

Говорят, что другие веб-серверы, такие как nginx, имеют больше возможностей в этой области. Может стоит проверить.

Я задал , по сути, тот же вопрос некоторое время назад. Может быть, есть какие-то идеи в обратной связи. Я реализовал вариант принятого ответа в проекте, о котором просил.

1 голос
/ 24 августа 2010

Вы можете использовать правила переписывания apache для маршрутизации запроса только через PHP, если запрошенный файл не существует.Таким образом, если у вас есть запрос на /images/logo.png и он существует, apache будет просто обслуживать его как обычно.

Это может сработать (я немного заржавел и ненавижу правила mod_rewrite: P)

# Route requests through PHP if the file does not exist
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ index.php?query=$1&%{QUERY_STRING} [L]

ОБНОВЛЕНИЕ:

Вы также можете просто определить, какие каталоги содержат статическое содержимое, и исключить их

RewriteCond %{REQUEST_URI} !^/images/.* [AND]
RewriteCond %{REQUEST_URI} !^/css/.*
RewriteRule ^(.*)$ index.php?query=$1&%{QUERY_STRING} [L]
0 голосов
/ 10 декабря 2013

Что вы могли бы сделать:

  • При входе в систему создайте случайную символьную ссылку (md5 ..), указывающую на ваши защищенные ресурсы.
  • Передайте этот путь клиенту
  • Некоторая логика для удаления этой символьной ссылки при выходе из системы или тайм-ауте.

Это только наполовину безопасно, особенно.если путь пройден без https.

ИЛИ:

  • иметь каталог в apache, защищенный IP.
  • иметь PHP, поддерживающий эту запись каталога (добавление и удаление разрешеноIP-адреса)
  • (для применения изменений необходимо «перезапустить службу httpd»)
0 голосов
/ 24 августа 2010

Используйте mod_mysql_auth для apache. это делает то, что вы пытаетесь сделать посмотрите на mod Auth MySQL под Apache 2 и Debian в качестве примера.

Я использовал это только один раз, но мне показалось, что он отлично работает.

0 голосов
/ 24 августа 2010

есть гораздо лучшие решения вашей проблемы.

но ваш ответ: используйте буферизацию вывода ob_start (); промывать(); это повысит вашу производительность.

но здесь у вас есть лучший подход:

для аутентифицированных пользователей служит ссылка, которая включает текущую метку времени и хэш имени файла / идентификатора, метку времени и секретный токен. Мэйби нравится так. $ link = $ timetamp. "/". md5 ($ secret_token. $ timestamp. $ filename). "/". $ filename.

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

таким образом, вы можете напрямую обслуживать файлы, защищенные через Apache. у вас также есть ip.

вы также можете проверить lighttpd, где что-то вроде taht уже существует в модуле с именем mod_secdownload. я думаю, что есть также плагины для Apache, и я уверен, что для Nginx

какая-то ссылка для вас:

http://redmine.lighttpd.net/wiki/1/Docs:ModSecDownload http://httpd.apache.org/docs/current/mod/mod_rewrite.html

0 голосов
/ 24 августа 2010

Похоже, вы пытаетесь написать свой собственный маленький веб-сервер там.Все, что вы пытаетесь сделать, Apache уже может сделать намного эффективнее.Я бы порекомендовал пересмотреть ваш подход.

...