summaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorElmer Miroslav Mosher Golovin <miroslav@mishamosher.com>2023-04-25 14:44:25 +0300
committerElmer Miroslav Mosher Golovin <miroslav@mishamosher.com>2023-04-26 16:39:25 +0300
commit585f1aba26b2c6a1a4fa1548cb3b0cb4e00b5d39 (patch)
tree3e7b9dd8f6d4f4da36f2582f5ddbd15862681637 /lib
parent9aed218ee1aead4c79a270fbd284d0dd4246ba91 (diff)
Avoid out-of-memory errors by using a resource instead of loading entire files into memory
Signed-off-by: Elmer Miroslav Mosher Golovin <miroslav@mishamosher.com>
Diffstat (limited to 'lib')
-rw-r--r--lib/Service/RecordingService.php46
1 files changed, 35 insertions, 11 deletions
diff --git a/lib/Service/RecordingService.php b/lib/Service/RecordingService.php
index 00dac2e26..a5c2defe4 100644
--- a/lib/Service/RecordingService.php
+++ b/lib/Service/RecordingService.php
@@ -2,7 +2,8 @@
declare(strict_types=1);
/**
- * @copyright Copyright (c) 2022 Vitor Mattos <vitor@php.rio>
+ * @copyright Copyright (c) 2022, Vitor Mattos <vitor@php.rio>
+ * @copyright Copyright (c) 2023, Elmer Miroslav Mosher Golovin (miroslav@mishamosher.com)
*
* @author Vitor Mattos <vitor@php.rio>
*
@@ -127,14 +128,16 @@ class RecordingService {
throw new InvalidArgumentException('owner_participant');
}
- $content = $this->getContentFromFileArray($file, $room, $participant);
+ $resource = $this->getResourceFromFileArray($file, $room, $participant);
$fileName = basename($file['name']);
- $this->validateFileFormat($fileName, $content);
+ $fileRealPath = realpath($file['tmp_name']);
+
+ $this->validateFileFormat($fileName, $fileRealPath);
try {
$recordingFolder = $this->getRecordingFolder($owner, $room->getToken());
- $fileNode = $recordingFolder->newFile($fileName, $content);
+ $fileNode = $recordingFolder->newFile($fileName, $resource);
$this->notifyStoredRecording($room, $participant, $fileNode);
} catch (NoUserException $e) {
throw new InvalidArgumentException('owner_invalid');
@@ -203,7 +206,15 @@ class RecordingService {
$this->notificationManager->notify($notification);
}
- public function getContentFromFileArray(array $file, Room $room, Participant $participant): string {
+ /**
+ * Gets a resource that represents the file contents of the file array.
+ *
+ * @param array $file File array from which a resource will be returned
+ * @param Room $room The Talk room that requests the resource
+ * @param Participant $participant The Talk participant that requests the resource
+ * @return resource Resource representing the file contents of the file array
+ */
+ public function getResourceFromFileArray(array $file, Room $room, Participant $participant) {
if ($file['error'] !== 0) {
$error = self::UPLOAD_ERRORS[$file['error']];
$this->logger->error($error);
@@ -220,17 +231,30 @@ class RecordingService {
throw new InvalidArgumentException('invalid_file');
}
- $content = file_get_contents($file['tmp_name']);
- unlink($file['tmp_name']);
+ $resource = fopen($file['tmp_name'], 'r');
+ if ($resource === false) {
+ throw new InvalidArgumentException('fopen_failed');
+ }
- if (!$content) {
+ $resourceStat = fstat($resource);
+ if ($resourceStat === false) {
+ throw new InvalidArgumentException('fstat_failed');
+ }
+
+ if ($resourceStat['size'] === 0) {
throw new InvalidArgumentException('empty_file');
}
- return $content;
+
+ return $resource;
}
- public function validateFileFormat(string $fileName, $content): void {
- $mimeType = $this->mimeTypeDetector->detectString($content);
+ public function validateFileFormat(string $fileName, string $fileRealPath): void {
+ if (!is_file($fileRealPath)) {
+ $this->logger->warning("An invalid file path ($fileRealPath) was provided");
+ throw new InvalidArgumentException('file_invalid_path');
+ }
+
+ $mimeType = $this->mimeTypeDetector->detectContent($fileRealPath);
$allowed = self::DEFAULT_ALLOWED_RECORDING_FORMATS;
if (!array_key_exists($mimeType, $allowed)) {
$this->logger->warning("Uploaded file detected mime type ($mimeType) is not allowed");