Кэширование PHP без вмешательства в права доступа к файлам (также, Как эмулировать переменные ASP-приложения в PHP)
Я пытаюсь реализовать какое-то кэширование в PHP-скрипте, который будет использоваться многими клиентами / сайтами, которые будут развернуты довольно нетехническими пользователями с использованием различных веб-хостов. Из-за нетехнического характера пользователей, я бы хотел не просить их настраивать права доступа к файлам. Кэширование должно происходить между сеансами, поэтому использование переменных сеанса запрещено. Если бы я кодировал это в ASP, я бы использовал переменные приложения, но они не существуют в PHP (насколько мне известно)
У кого-нибудь есть какие-либо предложения о том, как этого добиться?
Вот некоторые возможности, которые я рассмотрел, любые комментарии по ним будут полезны:
- Кэширование с помощью файлов в системных временных папках - я мог бы использовать sys_get_temp_dir() (или какую-нибудь аналогичную функцию на PHP4), чтобы помочь найти такую папку. Недостатком здесь является то, что он, вероятно, не будет работать на хостах, использующих ограничение openbase_dir
- На каком-то веб-сайте, на котором я смотрел, упоминалось, что PHP заставляет все пользовательские сеансы использовать одно и то же состояние сеанса, заставляя переменные сеанса действовать как переменные сеанса. Конечно, я не могу найти этот пост сейчас... В любом случае это кажется страшным. (Я обновлю этот вопрос ссылкой на этот пост, как только найду его снова)
- Использовать стороннее хранилище данных, такое как Amazon Simple Storage Service - похоже, излишне
- Кэшируйте данные на сервере, которым я управляю, и заставляйте клиента загружать оттуда новые данные при каждом попадании.
Еще раз, любые комментарии по этим идеям или любые новые будут оценены.
ОБНОВЛЕНИЕ: я пытался использовать session_id() для использования общего состояния сеанса, но это не работает. Каждый сеанс поддерживает свой собственный "GlobalCache", есть идеи почему?:
// This code doesn't work, but the similar code in my answer does!
function test() {
if (!$_SESSION['session_count']) $_SESSION['session_count'] = 0;
$_SESSION['session_count']++;
$count = get_cache( 'count' );
print "pre application count: $count<br>";
if ( !$count )
$count = 0;
$count++;
print "session_id: " . session_id() . "<br>";
print "post application count: $count<br>";
print "session_count: " . $_SESSION['session_count'] . "<br>";
set_cache('count', $count);
}
function set_cache( $name, $value ) {
$old_session = session_id();
print "old_session (set): $old_session<br>";
session_id("GlobalCache");
print "new_session (set): " . session_id() . "<br>";
$_SESSION[$name] = $value;
session_id( $old_session );
}
function get_cache( $name ) {
$old_session = session_id();
print "old_session (get): $old_session<br>";
session_id("GlobalCache");
print "new_session (get): " . session_id() . "<br>";
$value = $_SESSION[$name];
session_id( $old_session );
return $value;
}
session_start();
test();
ОБНОВЛЕНИЕ: некоторые предложили использовать memcached, который для некоторых является отличным решением, но, поскольку у меня нет контроля над средой конечного сервера, это не вариант. Идея состоит в том, чтобы иметь сценарий, с помощью которого люди могли бы просто подключиться по FTP к учетной записи общего хостинга, которая работает из коробки.
ОБНОВЛЕНИЕ: кто-то предложил создать мою собственную папку кэша со сценарием, но разве мне не нужно было создавать такую папку внутри папки, у которой уже были разрешения на запись?
ОБНОВЛЕНИЕ, РЕШЕНИЕ НАЙДЕНО: В итоге я выяснил проблемы в моем глобальном сценарии сеанса и опубликовал свой собственный ответ на этот счет. Спасибо всем за помощь.
6 ответов
Хорошо, я понял, как это сделать, эмулируя переменные приложения в стиле ASP, используя общее / глобальное состояние сеанса. Два ключевых изменения из моего нерабочего кода в соответствующем обновлении:
Чтобы переключить состояние сеанса, мы должны завершить текущий сеанс, переключиться на новый, а затем запустить его. Я инкапсулировал этот процесс в switch_session()
Так как мы меняем идентификаторы сеансов, мы должны буферизовать вывод страницы с помощью ob_start()/ob_end_flush(), чтобы cookie сеанса не отправлялись слишком рано.
Далее следует полный рабочий код (тоже вычищен!). Это можно легко проверить, загрузив страницу в IE и окне Firefox, и перезагрузив каждый раз несколько раз, чтобы увидеть рост счетчиков:
<?php
function test() {
// Do a regular session count
print "session_id: " . session_id() . "<br>";
if (!$_SESSION['session_count']) $_SESSION['session_count'] = 0;
$_SESSION['session_count']++;
print "session count: " . $_SESSION['session_count'] . "<br>";
// Do an application count
$count = get_cache( 'count' );
if ( !$count ) $count = 0;
$count++;
print "application count: $count<br>";
set_cache('count', $count);
}
function set_cache( $name, $value ) {
$old_session = switch_session("GlobalCache");
$_SESSION[$name] = $value;
switch_session( $old_session );
}
function get_cache( $name ) {
$old_session = switch_session("GlobalCache");
$value = $_SESSION[$name];
switch_session( $old_session );
return $value;
}
function switch_session( $session_id ) {
// switch the session and return the original
$old_id = session_id();
session_write_close();
session_id($session_id);
session_start();
return $old_id;
}
ob_start();
session_start();
test();
ob_end_flush();
?>
Используйте вашу собственную директорию кеша в директории вашего приложения. При этом вам не придется бороться с различными настройками сервера и / или PHP и получать лучшую переносимость.
Вы можете использовать сеансы с фиксированным ключом сеанса.
http://de.php.net/manual/en/function.session-id.php:
session_id ([id]) используется для получения или установки сессии
id
для текущей сессии. Если указан идентификатор, он заменит текущий идентификатор сессии. session_id() должен быть вызван перед session_start() для этой цели.
Я голосую за "Кэширование данных на сервере, которым я управляю, и чтобы клиент загружал оттуда новые данные при каждом обращении".
Все остальные пути ведут к определенному безумию.
Проверьте memcached для php- он работает очень хорошо.
Я использовал обновленную функцию автора как способ кэширования простого результата запроса к базе данных, так как ожидал высокой нагрузки. Я также сохранил временную метку, чтобы я мог определить, как часто страница будет обновлять результат базы данных, а не просто принимать кэшированное значение.
Я могу вам сказать, что эта функция кэширования имела намного худшую производительность, чем прямая обработка базы данных при каждом запросе. Я на самом деле убил сервер. Как только я переключился на простой запрос к базе данных, сервер заработал на полной скорости, и довольно большая нагрузка даже не была замечена.