@@ -112,6 +112,9 @@ public function getData() : array
112
112
*/
113
113
public function downloadAll ()
114
114
{
115
+ if (count ($ this ->getErrors ()) > 0 ) {
116
+ throw new BagItException ("The fetch.txt file has errors, unable to download files. " );
117
+ }
115
118
$ this ->resetErrors ();
116
119
$ this ->downloadQueue = [];
117
120
foreach ($ this ->files as $ file ) {
@@ -146,15 +149,36 @@ private function validateData(array $fetchData)
146
149
if (!$ this ->internalValidateUrl ($ uri )) {
147
150
throw new BagItException ("This library only supports http/https URLs " );
148
151
}
149
- if (!$ this ->validatePath ($ dest )) {
150
- // Skip destinations with %xx other than %0A, %0D and %25
151
- throw new BagItException ("Destination paths can't have any percent encoded characters except CR, LF, & % " );
152
- }
153
152
if (!$ this ->bag ->pathInBagData ($ dest )) {
154
153
throw new BagItException ("Path {$ dest } resolves outside the bag. " );
155
154
}
156
155
}
157
156
157
+ /**
158
+ * Add a file to this fetch file.
159
+ *
160
+ * @param string $url
161
+ * The remote URL for the file.
162
+ * @param string $destination
163
+ * The bag destination path for the file.
164
+ * @param int|null $size
165
+ * The expected size of the file, or null for unknown.
166
+ * @throws \whikloj\BagItTools\Exceptions\BagItException
167
+ * Errors with adding this file to your fetch file.
168
+ */
169
+ public function addFile (string $ url , string $ destination , int $ size = null ): void
170
+ {
171
+ $ fetchData = [
172
+ 'uri ' => $ url ,
173
+ 'destination ' => $ destination ,
174
+ ];
175
+ if (is_int ($ size )) {
176
+ $ fetchData ['size ' ] = $ size ;
177
+ }
178
+ // Download the file now to help with manifest handling, deleted when you package() or finalize().
179
+ $ this ->download ($ fetchData );
180
+ }
181
+
158
182
/**
159
183
* Download a single file as it is added to the fetch file so we can generate checksums.
160
184
*
@@ -327,13 +351,20 @@ private function loadFiles()
327
351
$ filesize = (int )$ filesize ;
328
352
}
329
353
$ destination = BagUtils::baseInData ($ matches [3 ]);
354
+ if (BagUtils::checkUnencodedFilepath ($ destination )) {
355
+ $ this ->addError (
356
+ "Line $ lineCount: Filepaths containing Line Feed (LF), Carriage Return (CR) or a " .
357
+ "percent sign (%) MUST be encoded, and only those characters can be encoded. "
358
+ );
359
+ }
360
+ $ destination = BagUtils::decodeFilepath ($ destination );
330
361
$ this ->files [] = [
331
362
'uri ' => $ uri ,
332
363
'size ' => $ filesize ,
333
364
'destination ' => $ destination ,
334
365
];
335
366
} else {
336
- $ this ->addError ("Line { $ lineCount} : This line is not valid. " );
367
+ $ this ->addError ("Line $ lineCount : This line is not valid. " );
337
368
}
338
369
}
339
370
}
@@ -513,7 +544,8 @@ private function writeToDisk()
513
544
throw new FilesystemException ("Unable to write {$ this ->filename }" );
514
545
}
515
546
foreach ($ this ->files as $ fileData ) {
516
- $ line = "{$ fileData ['uri ' ]} {$ fileData ['size ' ]} {$ fileData ['destination ' ]}" . PHP_EOL ;
547
+ $ destination = BagUtils::encodeFilepath ($ fileData ['destination ' ]);
548
+ $ line = "{$ fileData ['uri ' ]} {$ fileData ['size ' ]} $ destination " . PHP_EOL ;
517
549
$ line = $ this ->bag ->encodeText ($ line );
518
550
BagUtils::checkedFwrite ($ fp , $ line );
519
551
}
@@ -555,30 +587,6 @@ private function internalValidateUrl($url) : bool
555
587
return true ;
556
588
}
557
589
558
- /**
559
- * Validate the path for fetch files.
560
- *
561
- * @param string $dest
562
- * The destination file path.
563
- * @return bool
564
- * True if it is valid.
565
- */
566
- private function validatePath ($ dest ) : bool
567
- {
568
- // You can't have any encoded characters in the destination string except LF, CR, CRLF and % itself.
569
- if (strpos ($ dest , '% ' ) !== false ) {
570
- $ parts = explode ('% ' , $ dest );
571
- foreach ($ parts as $ part ) {
572
- $ char = substr ($ part , 0 , 2 );
573
- $ char = strtolower ($ char );
574
- if (!($ char == '0a ' || $ char == '0d ' || $ char == '25 ' )) {
575
- return false ;
576
- }
577
- }
578
- }
579
- return true ;
580
- }
581
-
582
590
/**
583
591
* Check if the url is already in the file.
584
592
*
0 commit comments