Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Sending Large Files #84

Open
solepixel opened this issue May 22, 2020 · 3 comments
Open

Sending Large Files #84

solepixel opened this issue May 22, 2020 · 3 comments

Comments

@solepixel
Copy link
Contributor

This issue is related to uploading larger files, such as 800MB and 1GB. The code I have for sending ALL files is the same:

public static function upload( $file, $folder_id ) {
	self::increase_all_the_limits();

	try {
		$folder = self::$client->getDriveItemById( $folder_id );
	} catch ( \Exception $e ) {
		self::log( 'There was an error getting OneDrive file properties for `' . $folder_id . '`: ' . $e->getMessage(), 'error' );
		return false;
	}

	try {
		$upload = $folder->startUpload( basename( $file ), fopen( $file, 'r' ), $args );
	} catch ( \Exception $e ) {
		self::log( 'Error: Could not initiate upload for `' . basename( $file ) . '`. Details: ' . $e->getMessage(), 'error' );
		return false;
	}

	try {
		$new_file = $upload->complete();
	} catch ( \Exception $e ) {
		self::log( 'Error: OneDrive upload failed for `' . basename( $file ) . '`. Details: ' . $e->getMessage(), 'error' );
		return false;
	}

	// Don't use isset or empty here.
	if ( ! $new_file->id ) {
		self::log( 'OneDrive upload status for `' . basename( $file ) . '` was missing ID property: ' . print_r( $new_file->id, true ), 'error' );
		return false;
	}

	return true;
}

During the $upload->complete() step, the entire file contents are retrieved, no matter what the file size. See:

      while (!$stream->eof()) {
            $rangeStream = new LimitStream($stream, $rangeSize, $offset);
            $rangeSize   = $rangeStream->getSize();
            $body        = $rangeStream->getContents();
            $rangeFirst  = $offset;
            $offset += $rangeSize;
            $rangeLast = $offset - 1;

            $headers = [
                'Content-Length' => $rangeSize,
                'Content-Range'  => "bytes $rangeFirst-$rangeLast/$size",
            ];

            $response = $this
                ->graph
                ->createRequest('PUT', $this->uploadUrl)
                ->addHeaders($headers)
                ->attachBody($body)
                ->execute();

            $status = $response->getStatus();

            if ($status == 200 || $status == 201) {
                $driveItem = $response->getResponseAsObject(DriveItem::class);

                return new DriveItemProxy(
                    $this->graph,
                    $driveItem,
                    $this->driveItemResourceDefinition
                );
            }

            if ($status != 202) {
                throw new \Exception("Unexpected status code produced by 'PUT {$this->uploadUrl}': $status");
            }
        }

Do you have an example of how to utilize the rangeSize option in the startUpload() $args to manually process the upload in chunks? Otherwise, do you have any suggestions? We continue to hit problems with timeouts, memory, and 503 Errors from OneDrive. It would be great to have a "status" returned during $upload->complete() or maybe even something like $upload->getStatus(), so I can close the request, and use the status to continue the upload on a new request. We've done something similar with Google Drive and Dropbox, but using the code above isn't quite cutting it for OneDrive. Thanks!

@krizalys
Copy link
Owner

@solepixel The code above is supposed to send your file in chunks, eg. this creates a 320KiB chunk:

new LimitStream($stream, $rangeSize, $offset);

Perhaps the code above is suffering from a memory leak on some systems, I will need to stress-test it a bit more.

Can you tell me the OS & PHP version you are using?

@solepixel
Copy link
Contributor Author

I believe it is sending in chunks, however there is no way to break the chunks into multiple requests, it tries to send the entire file all in the same process, so generally we're hitting 30sec timeout issues.

Tested on MacOS Catalina (10.15.4) and PHP 7.4.2 and PHP 7.3.9 as well as Ubuntu 14.04.6 with PHP 7.0.33 and PHP 7.4.6.

@ahsunali
Copy link

@krizalys thanks for the sdk.
I am trying to upload 2GB file and it is taking too long to upload, My hosting allowed max 15 min to a job and it break in the middle. However i can upload the same file to google-drive & ftp in seconds.

Do not know where actually the issue is, either it belongs to OneDrive or upload utility.
Need your help to identify the cause, as if it remains the same we need to close our account with OneDrive
Thanks!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants