У меня есть карточная игра (скриншот ниже), в которой я отображаю аватары игроков.
Для аватаров я написал короткий скрипт proxy.php, который будет принимать URL-адрес изображения, переданный ему в качестве параметра ? Img = , загружать его и сохранять в / var / www / cached_avatars / md5_of_that_url на моем компьютере с CentOS 5. В следующий раз, когда скрипт вызывается с тем же URL-адресом, он найдет это изображение в папке и отправит его непосредственно в STDOUT.
Это работает в основном хорошо, но для некоторых аватаров первоначальная загрузка не удалась (я полагаю, что время истекло), и вы не видите нижнюю часть изображения игрока:
Я хотел бы обнаружить этот сбой загрузки образа и удалить кэшированный частичный файл, чтобы он был повторно загружен при следующем вызове proxy.php.
Я пытался обнаружить события STREAM_NOTIFY_FAILURE или STREAM_NOTIFY_COMPLETED в моем обратном вызове, но они не запускаются. Я вижу только следующие события: STREAM_NOTIFY_CONNECT, STREAM_NOTIFY_MIME_TYPE_IS, STREAM_NOTIFY_FILE_SIZE_IS, STREAM_NOTIFY_REDIRECTED, STREAM_NOTIFY_PROGRESS:
Nov 3 18:48:27 httpd: 2 0
Nov 3 18:48:27 httpd: 4 image/jpeg 0
Nov 3 18:48:27 httpd: 5 Content-Length: 45842 0
Nov 3 18:48:27 httpd: 7 0
Nov 3 18:48:27 last message repeated 16 times
Nov 3 18:48:39 httpd: 2 0
Nov 3 18:48:40 httpd: 4 image/jpeg 0
Nov 3 18:48:40 httpd: 5 Content-Length: 124537 0
Nov 3 18:48:40 httpd: 7 0
И еще большая проблема в том, что я не могу передать переменные типа $ img или $ cached в обратный вызов или не могу установить переменную $ length в обратном вызове для события STREAM_NOTIFY_FILE_SIZE_IS, а затем сравнить его с размером файла ( $ cached) в основном скрипте (я мог обнаружить несоответствие и удалить файл):
Nov 3 18:50:17 httpd: PHP Notice: Undefined variable: length in /var/www/html/proxy.php on line 58
Nov 3 18:50:17 httpd: length=
У кого-нибудь есть решение моей проблемы?
Я посмотрел библиотеку PHP curl, но не понимаю, как она может мне здесь помочь.
Ниже приведен мой сценарий, я для краткости пропустил проверки работоспособности URL:
<?php
define('MAX_SIZE', 1024 * 1024);
define('CACHE_DIR', '/var/www/cached_avatars/');
$img = urldecode($_GET['img']);
$opts = array(
'http' => array(
'method' => 'GET'
)
);
$cached = CACHE_DIR . md5($img);
$finfo = finfo_open(FILEINFO_MIME);
$readfh = @fopen($cached, 'rb');
if ($readfh) {
header('Content-Type: ' . finfo_file($finfo, $cached));
header('Content-Length: ' . filesize($cached));
while (!feof($readfh)) {
$buf = fread($readfh, 8192);
echo $buf;
}
fclose($readfh);
finfo_close($finfo);
exit();
}
$ctx = stream_context_create($opts);
stream_context_set_params($ctx, array('notification' => 'callback'));
$writefh = fopen($cached, 'xb');
$webfh = fopen($img, 'r', FALSE, $ctx);
if ($webfh) {
$completed = TRUE;
while (!feof($webfh)) {
$buf = fread($webfh, 8192);
echo $buf;
if ($writefh)
fwrite($writefh, $buf);
}
fclose($webfh);
if ($writefh)
fclose($writefh);
# XXX can't access $length in callback
error_log('length=' . $length);
# XXX can't access $completed in callback
if (!$completed)
unlink($cached);
}
function callback($code, $severity, $message, $message_code, $bytes_transferred, $bytes_total) {
error_log(join(' ', array($code, $message, $message_code)));
if ($code == STREAM_NOTIFY_PROGRESS && $bytes_transferred > MAX_SIZE) {
exit('File is too big: ' . $bytes_transferred);
} else if ($code == STREAM_NOTIFY_FILE_SIZE_IS) {
if ($bytes_total > MAX_SIZE)
exit('File is too big: ' . $bytes_total);
else {
header('Content-Length: ' . $bytes_total);
# XXX can't pass to main script
$length = $bytes_total;
}
} else if ($code == STREAM_NOTIFY_MIME_TYPE_IS) {
if (stripos($message, 'image/gif') !== FALSE ||
stripos($message, 'image/png') !== FALSE ||
stripos($message, 'image/jpg') !== FALSE ||
stripos($message, 'image/jpeg') !== FALSE) {
header('Content-Type: ' . $message);
} else {
exit('File is not image: ' . $mime);
}
} else if ($code == STREAM_NOTIFY_FAILURE) {
$completed = FALSE;
}
}
?>
Я не использую блокировку файлов в моем скрипте: нормально, что чтение из кэша возвращает время от времени неполный файл (потому что он все еще загружается). Но я хочу, чтобы в моем кеше не было частично загруженных изображений. Также, если вы посмотрите на мой скрипт, я использую «xb», что должно предотвратить запись нескольких скриптов в 1 файл, поэтому это одновременное написание здесь не проблема.