Skip to content

Commit 3a799ea

Browse files
committed
Streaming and Saving Content from URL to File
Signed-off-by: rahul <[email protected]>
1 parent b69d48b commit 3a799ea

File tree

4 files changed

+119
-0
lines changed

4 files changed

+119
-0
lines changed

README.md

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,3 +111,13 @@ $fileEncryptor = new FileEncryptor('movie.csv', $secret);
111111
$fileEncryptor->decryptFile();
112112
113113
```
114+
115+
**Streaming and Saving Content from URL to File**
116+
117+
```
118+
119+
$url = "https://gist.github.com/rcsofttech85/629b37d483c4796db7bdcb3704067631#file-gistfile1-txt";
120+
$stream = new Stream($url, "outputFile.html");
121+
$stream->startStreaming();
122+
123+
```

src/Exception/StreamException.php

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<?php
2+
3+
namespace rcsofttech85\FileHandler\Exception;
4+
5+
use Exception;
6+
use Throwable;
7+
8+
class StreamException extends Exception
9+
{
10+
public function __construct($message = "could not stream file", $code = 0, Throwable $previous = null)
11+
{
12+
parent::__construct($message, $code, $previous);
13+
}
14+
}

src/Stream.php

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
<?php
2+
3+
namespace rcsofttech85\FileHandler;
4+
5+
use Fiber;
6+
use rcsofttech85\FileHandler\Exception\StreamException;
7+
use Throwable;
8+
9+
readonly class Stream
10+
{
11+
public function __construct(public string $streamUrl, public string $outputFilename)
12+
{
13+
}
14+
15+
/**
16+
* @throws StreamException
17+
*/
18+
public function startStreaming(): void
19+
{
20+
$fiber = new Fiber(function ($streamUrl): void {
21+
while (!feof($streamUrl)) {
22+
$contents = fread($streamUrl, 100);
23+
Fiber::suspend($contents);
24+
}
25+
});
26+
27+
$stream = fopen($this->streamUrl, 'r');
28+
if (!$stream) {
29+
throw new StreamException();
30+
}
31+
stream_set_blocking($stream, false);
32+
33+
$outputFile = fopen($this->outputFilename, 'w');
34+
35+
try {
36+
$content = $fiber->start($stream);
37+
while (!$fiber->isTerminated()) {
38+
fwrite($outputFile, $content);
39+
40+
$content = $fiber->resume();
41+
}
42+
} catch (Throwable $e) {
43+
throw new StreamException();
44+
} finally {
45+
fclose($stream);
46+
fclose($outputFile);
47+
}
48+
}
49+
}

tests/unit/StreamTest.php

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
<?php
2+
3+
namespace unit;
4+
5+
use PHPUnit\Framework\Attributes\Test;
6+
use PHPUnit\Framework\TestCase;
7+
use rcsofttech85\FileHandler\Exception\StreamException;
8+
use rcsofttech85\FileHandler\Stream;
9+
10+
class StreamTest extends TestCase
11+
{
12+
public static function setUpBeforeClass(): void
13+
{
14+
parent::setUpBeforeClass();
15+
16+
fopen("outputFile.html", "w");
17+
}
18+
19+
public static function tearDownAfterClass(): void
20+
{
21+
parent::tearDownAfterClass();
22+
unlink("outputFile.html");
23+
}
24+
25+
#[Test]
26+
public function streamAndWriteToFile()
27+
{
28+
$url = "https://gist.github.com/rcsofttech85/629b37d483c4796db7bdcb3704067631#file-gistfile1-txt";
29+
$stream = new Stream($url, "outputFile.html");
30+
$stream->startStreaming();
31+
32+
$this->assertGreaterThan(0, filesize("outputFile.html"));
33+
$this->assertStringContainsString('<!DOCTYPE html>', file_get_contents("outputFile.html"));
34+
$this->assertStringContainsString('</html>', file_get_contents("outputFile.html"));
35+
}
36+
37+
#[Test]
38+
public function throwExceptionIfUrlIsInvalid()
39+
{
40+
$url = "https://gist.github";
41+
$stream = new Stream($url, "outputFile.html");
42+
43+
$this->expectException(StreamException::class);
44+
$stream->startStreaming();
45+
}
46+
}

0 commit comments

Comments
 (0)