Storage::get

Reads a file from a disk and returns its raw contents as a string, or null when it is missing.

Signature
Storage::get(string $path): string|null
  • Added in Laravel 5.0

Parameters

ParameterTypeDescription
$$pathstringPath to the file, relative to the disk's configured root.

Return value

string|nullThe raw file contents as a string, or null when the file cannot be read and the disk is not configured to throw.

Errors

Returns null by default when the file is missing or unreadable. When the disk config sets 'throw' => true, a League\Flysystem\UnableToReadFile is thrown instead.

Changelog

  • PHP 11.xThe local disk's root moved to storage/app/private, so paths written by an older version of the application may no longer resolve after an upgrade.

Storage::get returns the whole file as a string. The path is relative to the disk root, and on a remote driver such as S3 this is a full download into PHP memory.

What trips people up

A missing file returns null; it does not throw. That surprises people, because a false-y string and a missing file then look the same, and the failure usually surfaces one line later as a null passed into json_decode or strlen. If you would rather fail loudly, set 'throw' => true on the disk and Flysystem raises UnableToReadFile with the underlying reason — which also distinguishes "not there" from "there but permission denied", something null cannot.

Checking exists first does not make the read safe. It is a second round trip and the file can vanish between the two calls; just check the return value.

When to reach for something else

  • Storage::json($path) reads and decodes JSON in one step, returning null on a missing or invalid file.
  • Storage::readStream($path) gives you a resource, which is what you want above a few megabytes — get holds the entire file in memory and will hit memory_limit.
  • Storage::download($path) builds a streamed response for the browser rather than materialising the bytes in your controller.

Example

Example · php
<?php

use Illuminate\Support\Facades\Storage;

Storage::disk('local')->put('exports/report.csv', "id,total\n1,99\n");

$csv = Storage::disk('local')->get('exports/report.csv');

echo $csv, PHP_EOL;

// A missing file is null, NOT an exception (unless the disk sets 'throw').
var_dump(Storage::disk('local')->get('exports/nope.csv'));   // NULL

// So check the return value rather than assuming a string.
if (($contents = Storage::disk('local')->get('exports/nope.csv')) === null) {
    echo 'not available', PHP_EOL;
}

// JSON in one step; also null on a missing or malformed file.
Storage::disk('local')->put('meta.json', '{"version":3}');
print_r(Storage::disk('local')->json('meta.json'));

When to use it

  • Read a stored JSON manifest back into an array during a scheduled reconciliation job.
  • Load a small template file from a tenant's disk to render an email.
  • Re-parse an uploaded CSV in a queued job using the path saved on the model.

Frequently asked questions

Does Storage::get throw an exception if the file does not exist?

No, it returns null by default. Add 'throw' => true to the disk's configuration array in config/filesystems.php and it throws League\Flysystem\UnableToReadFile instead, which also tells you whether the problem was a missing file or a permissions failure.

Should I call Storage::exists before Storage::get?

Generally not. It costs a second round trip — a real HTTP request on S3 — and the file can still disappear between the check and the read. Call get and test the result against null; use exists only when you need to branch without reading the contents.

How do I read a large file without running out of memory?

Use Storage::readStream($path), which returns a PHP resource you can consume line by line, or Storage::download($path) to stream it straight to the browser. get() materialises the whole file as a string and is bounded by memory_limit.

More examples

Making a missing file loud instead of null

Turning on throw converts a silent null into an exception naming the path, which is what you want on a disk holding data the application depends on. The trade-off is that every read path must now handle the exception; disks holding optional files are usually better left with the default. Note that throw also applies to writes.

Example · php
<?php

// config/filesystems.php
// 'local' => [
//     'driver' => 'local',
//     'root'   => storage_path('app/private'),
//     'throw'  => true,
// ],

use Illuminate\Support\Facades\Storage;
use League\Flysystem\UnableToReadFile;

try {
    $contents = Storage::disk('local')->get('invoices/missing.pdf');
} catch (UnableToReadFile $e) {
    echo $e->getMessage(), PHP_EOL;
    // Unable to read file from location: invoices/missing.pdf.
}

// Without 'throw' => true the same call is simply:
// var_dump(Storage::disk('local')->get('invoices/missing.pdf'));  // NULL
// ...and the real failure appears later, e.g.
// strlen(null) -> deprecation, or json_decode(null) -> null

Reading a large file without loading it into memory

readStream returns a PHP resource so the file is consumed a chunk at a time and memory stays flat regardless of size. The commented download call is the other half of the rule: a controller that returns a file should stream it rather than buffering the bytes only to echo them, which doubles memory use and delays the first byte.

Example · php
<?php

use Illuminate\Support\Facades\Storage;

// get() pulls the entire object into a PHP string.
// On a 2 GB export this dies at memory_limit.
// $csv = Storage::disk('s3')->get('exports/huge.csv');

$stream = Storage::disk('s3')->readStream('exports/huge.csv');

$rows = 0;

while (($line = fgets($stream)) !== false) {
    $rows++;
}

fclose($stream);

echo "{$rows} rows", PHP_EOL;

// To hand the file to the browser, do not read it at all:
// return Storage::disk('s3')->download('exports/huge.csv', 'report.csv');

Discussion

  • Be the first to comment on this lesson.