تابع stream_copy_to_stream() در PHP
تابع stream_copy_to_stream() یکی از توابع مفید PHP برای کپی دادهها بین دو استریم (resource) است. این تابع برای عملیاتهایی که نیاز به انتقال دادهها از یک منبع به مقصد دارند — مانند کپی فایلها، هدایت ورودی خام (php://input) به فایل، یا انتقال بین سوکتها — بسیار مناسب و کارآمد است.
امضای تابع و توضیح پارامترها
| امضا | int stream_copy_to_stream(resource $source, resource $dest [, int $maxlength = -1 [, int $offset = 0 ]]) |
|---|---|
| پارامترها |
|
| مقدار بازگشتی | تعداد بایتهای کپیشده (int) یا false در صورت خطا. |
نکات مهم
- پارامتر
$offsetزمانی کاربردی است که$sourceقابل seek باشد (مانند فایلها). روی سوکتها یاphp://inputقابل اطمینان نیست. - در عمل، این تابع معمولاً از حافظهٔ کمتری نسبت به خواندن کامل محتوای استریم در متغیر و سپس fwrite برخوردار است؛ بنابراین برای فایلهای بزرگ مناسب است.
- در صورت استفاده از
$maxlengthمیتوانید کپی جزئی انجام دهید (مثلاً کپی نخستین 1 مگابایت).
مثالهای کاربردی
مثال ۱ — کپی فایل به فایل (ساده و امن)
// Copy from one file to another
$src = fopen('large_input.bin', 'rb');
$dst = fopen('backup.bin', 'wb');
if ($src === false || $dst === false) {
throw new RuntimeException('Cannot open files');
}
$bytes = stream_copy_to_stream($src, $dst);
fclose($src);
fclose($dst);
echo "Copied $bytes bytesn";
این کد فایل large_input.bin را باز میکند و محتوا را مستقیماً به backup.bin مینویسد. در مقایسه با خواندن کامل فایل با file_get_contents و سپس file_put_contents، این روش حافظهٔ کمتری مصرف میکند و سریع است.
مثال ۲ — خواندن از ورودی خام و ذخیره به فایل
// Save raw POST body to a temporary file
$in = fopen('php://input', 'rb');
$tmp = fopen('php://temp', 'w+');
if ($in && $tmp) {
$bytes = stream_copy_to_stream($in, $tmp);
rewind($tmp);
// Now $tmp contains the request body; you can process it.
}
در این مثال دادهٔ ورودی HTTP (بدون پارس شدن مثل آپلودهای خام JSON یا وبهوکها) به یک استریم موقت نوشته میشود. استریم موقت (php://temp) تا سقف حافظه در رم میماند و بعد از آن به فایل تمپ منتقل میشود؛ بنابراین برای پردازش دادهٔ متوسط مناسب است.
مثال ۳ — کپی بخشی از فایل با استفاده از maxlength و offset
// Copy 1MB from offset 2MB of the source file
$src = fopen('bigfile.dat', 'rb');
$dst = fopen('part.dat', 'wb');
$bytes = stream_copy_to_stream($src, $dst, 1024 * 1024, 2 * 1024 * 1024);
fclose($src);
fclose($dst);
این نمونه نشان میدهد که میتوان از $maxlength و $offset برای کپی بخش خاصی از فایل استفاده کرد. توجه داشته باشید که اگر $src قابل seek نباشد، تعیین $offset ممکن است موفق نباشد یا به false منجر شود.
خطاها و مدیریت استثناها
قبل از فراخوانی تابع بهتر است بررسی کنید که منابع (resource) معتبر هستند. تابع در صورت بروز خطا false برمیگرداند؛ بنابراین همیشه مقدار بازگشتی را بررسی کنید و در صورت نیاز پیام خطا یا لاگ مناسب ثبت کنید.
نمونه کنترل خطا
$src = @fopen('file.bin', 'rb');
$dst = @fopen('out.bin', 'wb');
if (!$src || !$dst) {
error_log('Failed to open streams');
} else {
$copied = stream_copy_to_stream($src, $dst);
if ($copied === false) {
error_log('stream_copy_to_stream failed');
}
fclose($src);
fclose($dst);
}
در این کد از چک ساده برای جلوگیری از ادامهٔ عملیات در صورت باز نشدن فایلها استفاده شده است. در محیط تولیدی ممکن است بخواهید با try/catch و استثناها مدیریت پیشرفتهتری انجام دهید.
موارد پیشرفته و نکات بهینهسازی
- استفاده از فیلترهای استریم (stream_filter_append) برای پردازش آنلاین: مثلاً فشردهسازی یا تبدیل کدینگ هنگام کپی. این ترکیب بسیار قوی است چون تغییر داده بدون بارگزاری تمام محتوا در حافظه انجام میشود.
- مراقبت از استریمهای غیرقابل seek: برای سوکتها یا برخی ورودیها، offset عملی نیست. اگر نیاز به اسکیپ دارید، باید دادهها را خوانده و دور بریزید یا از مکانیزمهای دیگر استفاده کنید.
- به خاطر داشته باشید که
stream_copy_to_streamممکن است در برخی نسخهها با رفتارهای متفاوت در خصوص non-blocking کار کند؛ برای کار با سوکتها از گزینههای stream_set_blocking استفاده کنید.
مزایا نسبت به fgets/fread + fwrite در حلقه
- کد سادهتر و خواناتر.
- ممکن است پیادهسازی داخلی بهینهتری داشته باشد و کمتر حافظه مصرف کند.
- پشتیبانی از
$maxlengthو$offsetبه صورت مستقیم.
جمعبندی و استفادههای پیشنهادی
تابع stream_copy_to_stream() ابزار ساده و قدرتمندی برای جابجایی داده بین استریمها است. برای کپی فایلهای بزرگ، انتقال داده از/به استریمهای PHP (مثل php://input یا php://temp) و زمانی که میخواهید پردازشهایی را به صورت جریانمحور انجام دهید، بسیار مناسب است. هنگام کار با استریمهای غیرقابل seek یا سوکتها مراقب offset باشید و همواره مقدار بازگشتی را برای تشخیص خطا چک کنید.
اگر نیاز داشته باشید میتوان مثالهایی از ترکیب این تابع با stream_filter_append یا کار با سوکتها فراهم کرد.
آیا این مطلب برای شما مفید بود ؟



