@@ -134,6 +134,55 @@ public function __destruct()
134134 $ this ->close ();
135135 }
136136
137+ /**
138+ * PSR-7 immutability: clone yapıldığında resource'u derinleştir; aksi halde
139+ * iki Stream aynı resource handle'ını paylaşır, withBody dışı tüm withX
140+ * çağrıları orijinal mesajın body'sini de değiştirir.
141+ */
142+ public function __clone ()
143+ {
144+ if (!isset ($ this ->stream )) {
145+ return ;
146+ }
147+ $ this ->uri = null ;
148+ if (is_string ($ this ->stream )) {
149+ // String backend zaten PHP copy-on-write; ek iş gerekmiyor.
150+ return ;
151+ }
152+ if (!is_resource ($ this ->stream )) {
153+ return ;
154+ }
155+ $ originalPosition = @ftell ($ this ->stream );
156+ if ($ this ->seekable ) {
157+ @rewind ($ this ->stream );
158+ }
159+ $ contents = @stream_get_contents ($ this ->stream );
160+ if ($ contents === false ) {
161+ $ contents = '' ;
162+ }
163+ if ($ this ->seekable && is_int ($ originalPosition )) {
164+ @fseek ($ this ->stream , $ originalPosition );
165+ }
166+ $ copy = @fopen ('php://temp ' , 'w+b ' );
167+ if ($ copy === false ) {
168+ return ;
169+ }
170+ if ($ contents !== '' ) {
171+ fwrite ($ copy , $ contents );
172+ }
173+ // Orijinal stream'in pozisyonunu koru
174+ if (is_int ($ originalPosition )) {
175+ fseek ($ copy , $ originalPosition );
176+ } else {
177+ rewind ($ copy );
178+ }
179+ $ this ->stream = $ copy ;
180+ $ this ->size = strlen ($ contents );
181+ $ this ->seekable = true ;
182+ $ this ->readable = true ;
183+ $ this ->writable = true ;
184+ }
185+
137186 /**
138187 * @param null|string|resource|StreamInterface $body
139188 * @param string|null $target <p>["php://temp"|"php://memory"|NULL]</p>
@@ -155,6 +204,15 @@ public function init($body = null, ?string $target = 'php://temp'): StreamInterf
155204 }
156205 $ body = $ body ->getContents ();
157206 }
207+ // Resource'lar target'tan bağımsız her zaman kabul edilir
208+ if (is_resource ($ body )){
209+ $ this ->stream = $ body ;
210+ $ meta = stream_get_meta_data ($ this ->stream );
211+ $ this ->seekable = $ meta ['seekable ' ] && fseek ($ this ->stream , 0 , SEEK_CUR ) === 0 ;
212+ $ this ->readable = isset (self ::READ_WRITE_HASH ['read ' ][$ meta ['mode ' ]]);
213+ $ this ->writable = isset (self ::READ_WRITE_HASH ['write ' ][$ meta ['mode ' ]]);
214+ return $ this ;
215+ }
158216 if ($ this ->target === null ){
159217 if (!is_scalar ($ body )){
160218 throw new InvalidArgumentException ("The parameter \$body must be a string. " );
@@ -176,10 +234,7 @@ public function init($body = null, ?string $target = 'php://temp'): StreamInterf
176234 fwrite ($ resource , $ body );
177235 fseek ($ resource , 0 );
178236 }
179- $ body = $ resource ;
180- }
181- if (is_resource ($ body )){
182- $ this ->stream = $ body ;
237+ $ this ->stream = $ resource ;
183238 $ meta = stream_get_meta_data ($ this ->stream );
184239 $ this ->seekable = $ meta ['seekable ' ] && fseek ($ this ->stream , 0 , SEEK_CUR ) === 0 ;
185240 $ this ->readable = isset (self ::READ_WRITE_HASH ['read ' ][$ meta ['mode ' ]]);
0 commit comments