@@ -381,4 +381,70 @@ public function testAddContentMd5EmitsDeprecationNotice()
381381 restore_error_handler ();
382382 }
383383 }
384+
385+ /**
386+ * Tests that a user-provided PHP resource handle is NOT closed by
387+ * ObjectUploader after the upload completes (PutObject path).
388+ *
389+ * Regression test for: https://github.com/aws/aws-sdk-php/issues/XXXX
390+ * The cyclic reference fix (PR #3290) caused Stream::__destruct() to fire
391+ * promptly, which closed user-provided resource handles.
392+ */
393+ public function testUploadDoesNotCloseUserProvidedResourceHandle ()
394+ {
395+ $ client = $ this ->getTestClient ('S3 ' );
396+ $ this ->addMockResults ($ client , [new Result ()]);
397+
398+ $ fp = fopen ('php://memory ' , 'r+ ' );
399+ fwrite ($ fp , 'Hello, World! ' );
400+ fseek ($ fp , 0 );
401+
402+ (new ObjectUploader ($ client , 'bucket ' , 'key ' , $ fp ))->upload ();
403+
404+ $ this ->assertTrue (
405+ is_resource ($ fp ),
406+ 'User-provided resource handle should remain open after upload() '
407+ );
408+
409+ // Clean up
410+ fclose ($ fp );
411+ }
412+
413+ /**
414+ * Tests that a user-provided PHP resource handle is NOT closed by
415+ * ObjectUploader after the upload completes (multipart path).
416+ */
417+ public function testMultipartUploadDoesNotCloseUserProvidedResourceHandle ()
418+ {
419+ $ client = $ this ->getTestClient ('S3 ' );
420+ $ this ->addMockResults ($ client , [
421+ new Result (['UploadId ' => 'foo ' ]),
422+ new Result (['ETag ' => 'bar ' ]),
423+ new Result (['ETag ' => 'bar ' ]),
424+ new Result (['Location ' => 'https://bucket.s3.amazonaws.com/key ' ]),
425+ ]);
426+
427+ // Create a resource with content larger than the multipart threshold
428+ $ fp = fopen ('php://temp ' , 'r+ ' );
429+ $ data = str_repeat ('x ' , 6 * self ::MB );
430+ fwrite ($ fp , $ data );
431+ fseek ($ fp , 0 );
432+
433+ (new ObjectUploader (
434+ $ client ,
435+ 'bucket ' ,
436+ 'key ' ,
437+ $ fp ,
438+ 'private ' ,
439+ ['mup_threshold ' => 4 * self ::MB ]
440+ ))->upload ();
441+
442+ $ this ->assertTrue (
443+ is_resource ($ fp ),
444+ 'User-provided resource handle should remain open after multipart upload() '
445+ );
446+
447+ // Clean up
448+ fclose ($ fp );
449+ }
384450}
0 commit comments