From 7c2d04008df30360e5d9a2a53f42d77fa10757ea Mon Sep 17 00:00:00 2001 From: Jacek Kowalski <Jacek@jacekk.info> Date: Sat, 17 Aug 2024 20:08:50 +0000 Subject: [PATCH] Implement a timeout on fetch request --- lib/Fetch.php | 81 +++++++++++++++++++++++++++++++++------- 1 files changed, 67 insertions(+), 14 deletions(-) diff --git a/lib/Fetch.php b/lib/Fetch.php index 78e5bfe..8619456 100644 --- a/lib/Fetch.php +++ b/lib/Fetch.php @@ -20,7 +20,7 @@ if(!isset($url['pass'])) { $url['pass'] = 'anonymous@mpk.jacekk.net'; } - if($file == NULL) { + if($file === NULL) { $file = basename($url['path']); } @@ -37,34 +37,87 @@ $updated = FALSE; - if($localTime < $remoteTime || ($localTime == $remoteTime && $localSize != $remoteSize)) { - if(file_exists($file.'.tmp')) { - unlink($file.'.tmp'); - } - $ftp->get($file.'.tmp', $url['path'], FTP_BINARY); - touch($file.'.tmp', $remoteTime); - if(!rename($file.'.tmp', $file)) { - throw new Exception('Temporary file rename failed'); - } - $updated = TRUE; + if($localTime >= $remoteTime && $localSize == $remoteSize) { + return FALSE; } - return $updated; + if(file_exists($file.'.tmp')) { + unlink($file.'.tmp'); + } + $ftp->get($file.'.tmp', $url['path'], FTP_BINARY); + touch($file.'.tmp', $remoteTime); + if(!rename($file.'.tmp', $file)) { + throw new Exception('Temporary file rename failed'); + } + + return TRUE; + } + + static function parse_http_headers($headers) { + $hasHeader = FALSE; + foreach($headers as $header) { + if(substr($header, 0, 5) === 'HTTP/') { + $code = substr($header, 9, 3); + if($code === '304') { + return NULL; + } elseif(substr($code, 0, 1) == '2') { + $hasHeader = TRUE; + } + } elseif($hasHeader && strtolower(substr($header, 0, 15)) === 'last-modified: ') { + return strptime(substr($header, 15), 'D, d M Y H:i:s T'); + } + } + return FALSE; } static function generic($url, $file = NULL) { - if($file == NULL) { + if($file === NULL) { $file = basename($url['url']); } - $data = file_get_contents($url); + + $context = []; + if(is_file($file)) { + $file_date = filemtime($file); + $context['http'] = [ + 'header' => [ + 'If-Modified-Since: '.gmdate('D, d M Y H:i:s T', $file_date), + ], + 'timeout' => 15, + ]; + } + + $data = file_get_contents($url, FALSE, stream_context_create($context)); + $remoteTime = FALSE; + if(isset($http_response_header) && is_array($http_response_header)) { + $remoteTime = self::parse_http_headers($http_response_header); + if($remoteTime === NULL) { + return FALSE; + } + } + if($data === FALSE) { throw new Exception('URL fetch failed'); } if(file_put_contents($file.'.tmp', $data) === FALSE) { throw new Exception('Temporary file creation failed'); } + if($remoteTime !== FALSE) { + touch($file.'.tmp', $remoteTime); + } if(!rename($file.'.tmp', $file)) { throw new Exception('Temporary file rename failed'); } + + return TRUE; + } + + static function auto($url, $file = NULL) { + if($file === NULL) { + $file = basename($url['url']); + } + if(substr($url, 0, 4) == 'ftp:') { + return self::ftp($url, $file); + } + return self::generic($url, $file); } } -- Gitblit v1.9.1