@@ -85,15 +85,33 @@ public function addDownload($url, $mixed_filename)
85
85
86
86
// Use tmpfile() or php://temp to avoid "Too many open files" error.
87
87
if (is_callable ($ mixed_filename )) {
88
- $ callback = $ mixed_filename ;
89
- $ curl ->downloadCompleteCallback = $ callback ;
88
+ $ curl -> downloadCompleteCallback = $ mixed_filename ;
89
+ $ curl ->downloadFileName = null ;
90
90
$ curl ->fileHandle = tmpfile ();
91
91
} else {
92
92
$ filename = $ mixed_filename ;
93
- $ curl ->downloadCompleteCallback = function ($ instance , $ fh ) use ($ filename ) {
94
- file_put_contents ($ filename , stream_get_contents ($ fh ));
95
- };
93
+
94
+ // Use a temporary file when downloading. Not using a temporary file can cause an error when an existing
95
+ // file has already fully completed downloading and a new download is started with the same destination save
96
+ // path. The download request will include header "Range: bytes=$filesize-" which is syntactically valid,
97
+ // but unsatisfiable.
98
+ $ download_filename = $ filename . '.pccdownload ' ;
99
+
100
+ $ mode = 'wb ' ;
101
+ // Attempt to resume download only when a temporary download file exists and is not empty.
102
+ if (is_file ($ download_filename ) && $ filesize = filesize ($ download_filename )) {
103
+ $ mode = 'ab ' ;
104
+ $ first_byte_position = $ filesize ;
105
+ $ range = $ first_byte_position . '- ' ;
106
+ $ curl ->setOpt (CURLOPT_RANGE , $ range );
107
+ }
108
+ $ curl ->downloadFileName = $ download_filename ;
96
109
$ curl ->fileHandle = fopen ('php://temp ' , 'wb ' );
110
+
111
+ // Move the downloaded temporary file to the destination save path.
112
+ $ curl ->downloadCompleteCallback = function ($ instance , $ fh ) use ($ download_filename ) {
113
+ file_put_contents ($ download_filename , stream_get_contents ($ fh ));
114
+ };
97
115
}
98
116
99
117
$ curl ->setOpt (CURLOPT_FILE , $ curl ->fileHandle );
0 commit comments