Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

dust's avatar
Level 9

Populating database with images with Faker

I want to populate my database with images and in my UserFactory.php I have:

'picture' => $faker->image('public/storage/images',400,300) 

which puts some images in "public/storage/images".

The problem is that It fills that path in my database, and I can't access pictures because my browser wants to see the pictures in "storage/images." If I change path in code to "storage/images" Tinker complains that can't write in that directory "storage/images". So now I have to execute manualy query to fix path.

Is there a smarter way to do that?

  1. How to allow factory to write in "storage/images"?
  2. Is there a way to execute my query automaticaly after Faker finishes. I though about writing unittest so I can execute query imediately after factory but that is not test actualy.
  3. Something else smarter and elegant?
0 likes
30 replies
dust's avatar
Level 9

Hi @mdecooman I have a link already,

Changing to

'picture' => $faker->image('images',400,300)

Does not work for some reason: InvalidArgumentException with message 'Cannot write to directory "images"'

mdecooman's avatar

Hi @dust

Try this, should work. You need to tell Laravel the full path to use.

$filePath = storage_path('images');
'picture' => $faker->image($filePath,400,300)
mdecooman's avatar

Ah I forgot too. If you probably need to create the folders on the fly as well so add this to create the path if it doesn't exist:

$filepath = storage_path('images');

    if(!File::exists($filepath)){
        File::makeDirectory($filepath);  //follow the declaration to see the complete signature
    }
dust's avatar
Level 9

Hi @mdecooman , the folders are alreday created.

storage_path('images') does not work too. This time I'm getting: InvalidArgumentException with message 'Cannot write to directory "/var/www/html/resources/examples/storage/images"' This directory does not exists, because it is wrong. But I get your idea and changed to:

$filePath = public_path('storage/images');

which works but adds full path before image: /var/www/html/resources/examples/public/storage/images/e170165d83e9fbae88360c283e04df7d.jpg

And my browser didn't like it again. It wants: storage/images/e170165d83e9fbae88360c283e04df7d.jpg

mdecooman's avatar

Hi @dust

Just out of curiousity, can you tweak your user factory model to add an avatar?

Add the column avatar in your db, then modify the factory model for user

$factory->define(App\User::class, function (Faker\Generator $faker) {
    static $password;

    $filepath = storage_path('avatars');

    if(!File::exists($filepath)){
        File::makeDirectory($filepath);
    }

    return [
        'name' => $faker->name,
        'email' => $faker->unique()->safeEmail,
        'password' => $password ?: $password = bcrypt('secret'),
        'remember_token' => str_random(10),
        'avatar' => $faker->image($filepath,400, 300)
    ];

Then in Tinker just create a new user (this example is the result of a successful test on my Mac)

>>> factory('App\User')->create();
=> App\User {#856
     name: "Lloyd Keeling",
     client_id: 17,
     email: "iliana01@example.net",
     avatar: "/the/path/to/laravel/storage/avatars/07abbdfe78165d505710148c290f9289.jpg",
     updated_at: "2017-04-18 19:54:18",
     created_at: "2017-04-18 19:54:18",
     id: 13,
   }

What is your environment? I would look into the user running your web server and its permissions.

dust's avatar
Level 9

Hi @mdecooman and sorry for late replay.

No this does not solve my issue :(

If I tweak my factory model it creates folder and image in that folder, but it is not displayed - 404. The path is "full-project-path/storage/avatars/avatar.jpg"

After tweaking my image path in browser I found, that I can only show images from my public directory. In my case "/public/storage/avatars/avatar.jpg"

So in this case it is better to use public_path(), but either ways I have to edit my path in DB because "full-project-path/public/storage/avatars/avatar.jpg" in browser does not show anything.

In my view i have:

<img src="{{ $item->picture }}" >

or

<img src="{{ $user->avatar }}" >
mdecooman's avatar

@dust

The public folder needs a symlink to your storage. That is why the php artisan command, exists:

php artisan storage:link

So you should be able to use your storage_path() (remove the avatars folder form your public before)

dust's avatar
Level 9

About environment I'm on Linux machine with apache web server and php 7.1. Later I'll test on mac with MAMP Pro.

dust's avatar
Level 9

I alreday made a link with:

php artisan storage:link

If I run this again I'm getting: The "public/storage" directory already exists.

The link is from "public/storage" to "storage/app/public"

And storage_path() writes in "storage"

mdecooman's avatar

@dust

Yeah indeed... I wrote too fast.

The issue is from faker basically that writes the wrong path in DB. In the meantime, since it is just for test purposes or view design, I would use the

'image' => $faker->imageUrl(400, 300)

Then once you do upload avatars or else from your UI, you can get the path right from your controller. Will keep digging since I want to get the solution too.

mdecooman's avatar
Level 19

@dust

From the faker github, we can see the signature of the image function

public static function image($dir = null, $width = 640, $height = 480, $category = null, $fullPath = true, $randomize = true, $word = null)

// setting the $fullPath = false  should solve our issue (testing now)

So a solution is:

'picture' => $faker->image('public/storage/images',400,300, null, false) 

and in your view you just do sthg similar as

<img src="/my/path/{{ $item->picture }}" >
19 likes
napestershine's avatar

Hi @mdecooman

I tried above method, but it says

[InvalidArgumentException]
  Cannot write to directory "public/uploads/homeslider"

In my Modelfactory I have written like:

'image' =>  $faker->image('public/uploads/homeslider',640,480, null, false) 

Any solution?

Thank you

dust's avatar
Level 9

I'm not sure that you can write in public directory that way.

You'll have to make a link:

php artisan storage:link

This will make a link named storage in your public directory which points to storage/app/public.

Then put your files in public/storage. For example /public/storage/uploads/homeslider

Modify your code and try again.

2 likes
mdecooman's avatar

Hi @napestershine

 $faker->image('public/uploads/homeslider',640,480, null, false) 

will try to create the file from the storage folder so as @dust mentioned, you need to create a symlink to connect the storage to public and make sure you have the corresponding path.

//so basically you need to do the symlink and change, for example like

 $faker->image('app/public/images',640,480, null, false) 

// which would correspond to call from your view
<img src="/images/{{ $item->picture }}" >

Not tested but you get the principle.

PS: Read carefully the documentation of Laravel, it will give you all the clues. Problem is that we often read too fast the doc when every line matters...

Let us know if you still have issues.

1 like
mdecooman's avatar

In addition when the folder does not exist you can do this before.

$filepath = storage_path('app/public/images');
    if(!File::exists($filepath)){
        File::makeDirectory($filepath);
    }

and use the variable instead for the paths

$faker->image($filepath,640,480, null, false) 
4 likes
duytong's avatar

I tried to follow but received an error

PHP warning:  unlink(D:\Xamp2\htdocs\www\medium\storage\app/public/images\48b75cb7e78c79ded34b101fce0a401d.jpg): Resource temporarily unavailable in D:\Xamp2\htdocs\www\medium\vendor\fzaninotto\faker\src\Faker\Provider\Image.php on line 91

Any help?

golpaj's avatar

I have get the same problem :

PHP Warning: unlink(public/images\a8d2c96e42f0374f32821f901cbfbe9c.jpg): Resource temporarily unavailable in C:\wamp64\www\cmiejsce\vendor\fzaninotto\faker\src\Faker\Provider\Image.php on line 91

the code is :

$factory->define(App\Photo::class, function (Faker $faker) {

return [
   'file' => $faker->image('public/images',400,300, null, false)
  
];

});

1 like
golpaj's avatar

I found a solution in -> Faker\Provider\Image.php you must add curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

if (function_exists('curl_exec')) { // use cURL //$fp = fopen($filepath, 'w'); $fp = fopen($filepath, 'w+');

        $ch = curl_init($url);

         curl_setopt($ch, CURLOPT_FILE, $fp); //true

        curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, 0);

        $success = curl_exec($ch) && curl_getinfo($ch, CURLINFO_HTTP_CODE) === 200;


        if ($success) {
            fclose($fp);
        } else {

            unlink($filepath);
        }


        curl_close($ch);

}

iamtoddperkins's avatar

For anyone looking for an alternative solution, that will probably look more like how your real code is setup:


use Faker\Generator as Faker;
use Illuminate\Http\File;
use Illuminate\Support\Facades\Storage;

$factory->define(App\MyModel::class, function (Faker $faker) {

$image = $faker->image(); $imageFile = new File($image);

return [ 'image' => Storage::disk('public')->putFile('images', $imageFile), ];

});

7 likes
Griehle's avatar

Could you do this kind of thing with Audio files? Using Factories for dev. How would you do that and be able to test if it plays after playlist creation and such. Or would you use some kind of dummy file that doesn't actually play?

Hadayat's avatar

@mdecooman Thanks for the solution, it works for me, I ask you one more question, how we can set the $faker image name in the database because now it's generating image name like "6f80f67fc51796a2f52fcd8fe5b24678.jpg".

yaddly's avatar

Hi @dust, I know this was long answered by @mdecooman but I would like to share a solution that borrows mostly from what @mdecooman has proposed but adds the smart portion you alluded to in your question.

private function imageGenerator(): string
    {
        $photo_path = storage_path('app/public/profile-photos');

        if (!File::exists($photo_path)) {
            File::makeDirectory($photo_path);
        }
		//Alternative Solution 1
		//$photo_path = $this->faker->image(dir: $photo_path, width: 948, height: 1080, fullPath: false);
        //$photo_path = 'profile-photos/' . $photo_path;

		//Alternative Solution 2
        $photo_path = $this->faker->image(dir: $photo_path, width: 948, height: 1080);

        $token = 'profile';

        if (($offset = strpos($photo_path, $token)) !== false) {
            $photo_path = substr($photo_path, $offset);

            //$photo_path = explode('app/public/', $photo_path, 2)[1];
        }

        return $photo_path;
    }

Please or to participate in this conversation.