fix download large file for map download
This commit is contained in:
@@ -36,6 +36,7 @@ class AsyncHttpRequest implements UsageInformationAble {
|
|||||||
private $contentType = 'text/xml; charset=UTF-8;';
|
private $contentType = 'text/xml; charset=UTF-8;';
|
||||||
private $timeout = 60;
|
private $timeout = 60;
|
||||||
private $headers = array();
|
private $headers = array();
|
||||||
|
private $handle = null;
|
||||||
|
|
||||||
public function __construct($maniaControl, $url) {
|
public function __construct($maniaControl, $url) {
|
||||||
$this->maniaControl = $maniaControl;
|
$this->maniaControl = $maniaControl;
|
||||||
@@ -57,8 +58,7 @@ class AsyncHttpRequest implements UsageInformationAble {
|
|||||||
->set(CURLOPT_USERAGENT, 'ManiaControl v' . ManiaControl::VERSION)// user-agent
|
->set(CURLOPT_USERAGENT, 'ManiaControl v' . ManiaControl::VERSION)// user-agent
|
||||||
->set(CURLOPT_RETURNTRANSFER, true)//
|
->set(CURLOPT_RETURNTRANSFER, true)//
|
||||||
->set(CURLOPT_FOLLOWLOCATION, true)// support redirect
|
->set(CURLOPT_FOLLOWLOCATION, true)// support redirect
|
||||||
->set(CURLOPT_SSL_VERIFYPEER, false)
|
->set(CURLOPT_SSL_VERIFYPEER, false);
|
||||||
->set(CURLOPT_HEADER, true);
|
|
||||||
return $request;
|
return $request;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -76,9 +76,15 @@ class AsyncHttpRequest implements UsageInformationAble {
|
|||||||
array_push($this->headers, 'Accept-Charset: utf-8');
|
array_push($this->headers, 'Accept-Charset: utf-8');
|
||||||
|
|
||||||
$request = $this->newRequest($this->url, $this->timeout);
|
$request = $this->newRequest($this->url, $this->timeout);
|
||||||
$request->getOptions()->set(CURLOPT_AUTOREFERER, true)// accept link reference
|
$request->getOptions()
|
||||||
|
->set(CURLOPT_AUTOREFERER, true)// accept link reference
|
||||||
->set(CURLOPT_HTTPHEADER, $this->headers); // headers
|
->set(CURLOPT_HTTPHEADER, $this->headers); // headers
|
||||||
|
|
||||||
|
if ($this->handle !== null) {
|
||||||
|
$request->getOptions()
|
||||||
|
->set(CURLOPT_FILE, $this->handle);
|
||||||
|
}
|
||||||
|
|
||||||
$this->processRequest($request);
|
$this->processRequest($request);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -287,4 +293,22 @@ class AsyncHttpRequest implements UsageInformationAble {
|
|||||||
public function setTimeout($timeout) {
|
public function setTimeout($timeout) {
|
||||||
$this->timeout = $timeout;
|
$this->timeout = $timeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the File Resource handle
|
||||||
|
*
|
||||||
|
* @return int
|
||||||
|
*/
|
||||||
|
public function getHandle() {
|
||||||
|
return $this->handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets the File Resource handle
|
||||||
|
*
|
||||||
|
* @param int $handle
|
||||||
|
*/
|
||||||
|
public function setHandle($handle) {
|
||||||
|
$this->handle = $handle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@@ -630,9 +630,18 @@ class DirectoryBrowser implements ManialinkPageAnswerListener {
|
|||||||
$folderPath = $player->getCache($this, self::CACHE_FOLDER_PATH);
|
$folderPath = $player->getCache($this, self::CACHE_FOLDER_PATH);
|
||||||
if (filter_var($url, FILTER_VALIDATE_URL)) {
|
if (filter_var($url, FILTER_VALIDATE_URL)) {
|
||||||
|
|
||||||
|
try {
|
||||||
|
$tempFile = tempnam(sys_get_temp_dir(), 'map_');
|
||||||
|
$fp = fopen($tempFile, 'w+');
|
||||||
|
|
||||||
|
$this->maniaControl->getChat()->sendSuccess('Starting download...', $player);
|
||||||
|
|
||||||
$asyncHttpRequest = new AsyncHttpRequest($this->maniaControl, $url);
|
$asyncHttpRequest = new AsyncHttpRequest($this->maniaControl, $url);
|
||||||
$asyncHttpRequest->setCallable(function ($file, $error, $headers) use ($url, $folderPath, $player) {
|
$asyncHttpRequest->setHandle($fp);
|
||||||
if (!$file || $error) {
|
$asyncHttpRequest->setCallable(function ($file, $error, $headers) use ($url, $folderPath, $tempFile, $fp, $player) {
|
||||||
|
// closing file handle
|
||||||
|
fclose($fp);
|
||||||
|
if ($error) {
|
||||||
$message = "Impossible to download the file: " . $error;
|
$message = "Impossible to download the file: " . $error;
|
||||||
$this->maniaControl->getChat()->sendError($message, $player);
|
$this->maniaControl->getChat()->sendError($message, $player);
|
||||||
Logger::logError(AuthenticationManager::getAuthLevelName($player->authLevel) .' "'. $player->nickname . '" ('. $player->login .') encountered an error during the download of the zip file "'. $url .'": '. $error);
|
Logger::logError(AuthenticationManager::getAuthLevelName($player->authLevel) .' "'. $player->nickname . '" ('. $player->login .') encountered an error during the download of the zip file "'. $url .'": '. $error);
|
||||||
@@ -641,12 +650,9 @@ class DirectoryBrowser implements ManialinkPageAnswerListener {
|
|||||||
$filePath = "";
|
$filePath = "";
|
||||||
|
|
||||||
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
$finfo = new finfo(FILEINFO_MIME_TYPE);
|
||||||
if ($finfo->buffer($file) === "application/zip") {
|
|
||||||
$zip = new ZipArchive();
|
|
||||||
|
|
||||||
// Create a temporary file
|
if ($finfo->file($tempFile) === "application/zip") {
|
||||||
$tempFile = tempnam(sys_get_temp_dir(), 'zip');
|
$zip = new ZipArchive();
|
||||||
file_put_contents($tempFile, $file);
|
|
||||||
|
|
||||||
$open = $zip->open($tempFile);
|
$open = $zip->open($tempFile);
|
||||||
|
|
||||||
@@ -720,6 +726,10 @@ class DirectoryBrowser implements ManialinkPageAnswerListener {
|
|||||||
$message = "File is not a map: " . $fileName;
|
$message = "File is not a map: " . $fileName;
|
||||||
$this->maniaControl->getChat()->sendError($message, $player);
|
$this->maniaControl->getChat()->sendError($message, $player);
|
||||||
Logger::logError(AuthenticationManager::getAuthLevelName($player->authLevel) .' "'. $player->nickname . '" ('. $player->login .') encountered an error when downloadeding the map file "'. $fileName .'": File is not a map');
|
Logger::logError(AuthenticationManager::getAuthLevelName($player->authLevel) .' "'. $player->nickname . '" ('. $player->login .') encountered an error when downloadeding the map file "'. $fileName .'": File is not a map');
|
||||||
|
|
||||||
|
// Clean up the temporary file
|
||||||
|
unlink($tempFile);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@@ -742,11 +752,16 @@ class DirectoryBrowser implements ManialinkPageAnswerListener {
|
|||||||
}
|
}
|
||||||
$filePath = substr($filePath, 0, -8) . "-" . $index . ".Map.Gbx";
|
$filePath = substr($filePath, 0, -8) . "-" . $index . ".Map.Gbx";
|
||||||
}
|
}
|
||||||
$bytes = file_put_contents($filePath, $file);
|
|
||||||
if (!$bytes || $bytes <= 0) {
|
$renamed = rename($tempFile, $filePath);
|
||||||
|
if (!$renamed) {
|
||||||
$message = "Failed to write file " . $filePath;
|
$message = "Failed to write file " . $filePath;
|
||||||
$this->maniaControl->getChat()->sendError($message, $player);
|
$this->maniaControl->getChat()->sendError($message, $player);
|
||||||
Logger::logError(AuthenticationManager::getAuthLevelName($player->authLevel) .' "'. $player->nickname . '" ('. $player->login .') encountered an error when downloadeding the map file "'. $fileName .'": Failed to write the file');
|
Logger::logError(AuthenticationManager::getAuthLevelName($player->authLevel) .' "'. $player->nickname . '" ('. $player->login .') encountered an error when downloadeding the map file "'. $fileName .'": Failed to write the file');
|
||||||
|
|
||||||
|
// Clean up the temporary file
|
||||||
|
unlink($tempFile);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -760,6 +775,10 @@ class DirectoryBrowser implements ManialinkPageAnswerListener {
|
|||||||
});
|
});
|
||||||
|
|
||||||
$asyncHttpRequest->getData();
|
$asyncHttpRequest->getData();
|
||||||
|
} catch (\Throwable $th) {
|
||||||
|
Logger::logError('Error when downloading file: '. $th->getMessage());
|
||||||
|
$this->maniaControl->getChat()->sendError('Error when downloading file: '. $th->getMessage(), $player);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@@ -47,8 +47,7 @@ abstract class WebReader {
|
|||||||
->set(CURLOPT_USERAGENT, 'ManiaControl v' . ManiaControl::VERSION)// user-agent
|
->set(CURLOPT_USERAGENT, 'ManiaControl v' . ManiaControl::VERSION)// user-agent
|
||||||
->set(CURLOPT_RETURNTRANSFER, true)// return instead of output content
|
->set(CURLOPT_RETURNTRANSFER, true)// return instead of output content
|
||||||
->set(CURLOPT_AUTOREFERER, true)// follow redirects
|
->set(CURLOPT_AUTOREFERER, true)// follow redirects
|
||||||
->set(CURLOPT_SSL_VERIFYPEER, false)
|
->set(CURLOPT_SSL_VERIFYPEER, false);
|
||||||
->set(CURLOPT_HEADER, true);;
|
|
||||||
return $request;
|
return $request;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -6,7 +6,7 @@ use Symfony\Component\EventDispatcher\EventDispatcher;
|
|||||||
class Request extends EventDispatcher implements RequestInterface
|
class Request extends EventDispatcher implements RequestInterface
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* @var resource cURL handler
|
* @var \CurlHandle cURL handler
|
||||||
*/
|
*/
|
||||||
protected $ch;
|
protected $ch;
|
||||||
|
|
||||||
@@ -20,6 +20,11 @@ class Request extends EventDispatcher implements RequestInterface
|
|||||||
*/
|
*/
|
||||||
protected $options = null;
|
protected $options = null;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var array Response Headers feed by the CURLOPT_HEADERFUNCTION callback
|
||||||
|
*/
|
||||||
|
protected $responseHeaders;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create new cURL handle
|
* Create new cURL handle
|
||||||
*
|
*
|
||||||
@@ -30,6 +35,35 @@ class Request extends EventDispatcher implements RequestInterface
|
|||||||
if ($url !== null) {
|
if ($url !== null) {
|
||||||
$this->getOptions()->set(CURLOPT_URL, $url);
|
$this->getOptions()->set(CURLOPT_URL, $url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$this->getOptions()->set(CURLOPT_HEADERFUNCTION, function($ch, $headerLine) {
|
||||||
|
$len = strlen($headerLine);
|
||||||
|
|
||||||
|
// Handle HTTP status lines (e.g., HTTP/1.1 200 OK)
|
||||||
|
if (preg_match('/^HTTP\/\d\.\d\s+\d+/', $headerLine)) {
|
||||||
|
$this->responseHeaders = []; // Reset on redirect or multiple responses
|
||||||
|
}
|
||||||
|
|
||||||
|
$parts = explode(':', $headerLine, 2);
|
||||||
|
if (count($parts) === 2) {
|
||||||
|
$key = strtolower(trim($parts[0]));
|
||||||
|
$value = trim($parts[1]);
|
||||||
|
|
||||||
|
// Handle multiple headers with same name
|
||||||
|
if (!isset($this->responseHeaders[$key])) {
|
||||||
|
$this->responseHeaders[$key] = $value;
|
||||||
|
} else {
|
||||||
|
if (is_array($this->responseHeaders[$key])) {
|
||||||
|
$this->responseHeaders[$key][] = $value;
|
||||||
|
} else {
|
||||||
|
$this->responseHeaders[$key] = [$this->responseHeaders[$key], $value];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $len;
|
||||||
|
});
|
||||||
|
|
||||||
$this->ch = curl_init();
|
$this->ch = curl_init();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -72,7 +106,7 @@ class Request extends EventDispatcher implements RequestInterface
|
|||||||
/**
|
/**
|
||||||
* Returns cURL raw resource
|
* Returns cURL raw resource
|
||||||
*
|
*
|
||||||
* @return resource cURL handle
|
* @return \CurlHandle cURL handle
|
||||||
*/
|
*/
|
||||||
public function getHandle()
|
public function getHandle()
|
||||||
{
|
{
|
||||||
@@ -90,6 +124,16 @@ class Request extends EventDispatcher implements RequestInterface
|
|||||||
return (int)$this->ch;
|
return (int)$this->ch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the response headers
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function getResponseHeaders()
|
||||||
|
{
|
||||||
|
return $this->responseHeaders;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Perform a cURL session.
|
* Perform a cURL session.
|
||||||
* Equivalent to curl_exec().
|
* Equivalent to curl_exec().
|
||||||
@@ -108,6 +152,7 @@ class Request extends EventDispatcher implements RequestInterface
|
|||||||
$content = curl_exec($this->ch);
|
$content = curl_exec($this->ch);
|
||||||
|
|
||||||
$response = new Response($this, $content);
|
$response = new Response($this, $content);
|
||||||
|
$response->setHeaders($this->responseHeaders);
|
||||||
$errorCode = curl_errno($this->ch);
|
$errorCode = curl_errno($this->ch);
|
||||||
if ($errorCode !== CURLE_OK) {
|
if ($errorCode !== CURLE_OK) {
|
||||||
$response->setError(new Error(curl_error($this->ch), $errorCode));
|
$response->setError(new Error(curl_error($this->ch), $errorCode));
|
||||||
|
@@ -11,7 +11,7 @@ class RequestsQueue extends EventDispatcher implements RequestsQueueInterface, \
|
|||||||
protected $defaultOptions = null;
|
protected $defaultOptions = null;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @var resource cURL multi handler
|
* @var \CurlMultiHandle cURL multi handler
|
||||||
*/
|
*/
|
||||||
protected $mh;
|
protected $mh;
|
||||||
|
|
||||||
@@ -115,6 +115,7 @@ class RequestsQueue extends EventDispatcher implements RequestsQueueInterface, \
|
|||||||
$event = new Event();
|
$event = new Event();
|
||||||
$event->request = $request;
|
$event->request = $request;
|
||||||
$event->response = new Response($request, curl_multi_getcontent($request->getHandle()));
|
$event->response = new Response($request, curl_multi_getcontent($request->getHandle()));
|
||||||
|
$event->response->setHeaders($event->request->getResponseHeaders());
|
||||||
if ($result !== CURLE_OK) {
|
if ($result !== CURLE_OK) {
|
||||||
$event->response->setError(new Error(curl_error($request->getHandle()), $result));
|
$event->response->setError(new Error(curl_error($request->getHandle()), $result));
|
||||||
}
|
}
|
||||||
|
@@ -19,18 +19,7 @@ class Response
|
|||||||
$this->ch = $request->getHandle();
|
$this->ch = $request->getHandle();
|
||||||
|
|
||||||
if ($content != null) {
|
if ($content != null) {
|
||||||
$header_size = $this->getInfo(CURLINFO_HEADER_SIZE);
|
$this->content = $content;
|
||||||
|
|
||||||
foreach (explode("\r\n", substr($content, 0, $header_size)) as $value) {
|
|
||||||
if(false !== ($matches = explode(':', $value, 2))) {
|
|
||||||
if (count($matches) === 2) {
|
|
||||||
$headers_arr["{$matches[0]}"] = trim($matches[1]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
$this->headers = $headers_arr;
|
|
||||||
|
|
||||||
$this->content = substr($content, $header_size);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,6 +78,17 @@ class Response
|
|||||||
return isset($this->error);
|
return isset($this->error);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Sets headers
|
||||||
|
*
|
||||||
|
* @param array $error headers to set
|
||||||
|
* @return void
|
||||||
|
*/
|
||||||
|
public function setHeaders(array $headers)
|
||||||
|
{
|
||||||
|
$this->headers = $headers;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns headers of request
|
* Returns headers of request
|
||||||
*
|
*
|
||||||
|
Reference in New Issue
Block a user