fzaninotto/Faker

Lorempixel is down : impossible to use $faker->image (again)

dsampaolo opened this issue Β· 28 comments

Summary

LoremPixel.com is used by $faker->image to download files from the service.

The service is down, so we can't use $faker->image() at the moment.

We use it in the seeds of a Laravel application, which disables our preproduction environment.

A timeout detection MAY be enough for us, as it would allow the preproduction environment to run, even without images.

Bonjour J'aurai juste aimΓ© savoir quand sera rΓ©parer ( $ faker -> image )
Je vous remecie beaucoup !!!

this service nonsence. πŸ‘Ž
please replace this service with another one.

This is temporary fix in my project. Feel free to use if the random image is sufficient for you with random color only:

    /**
     * Generates random image; temporary fix for current issue.
     * @link https://github.com/fzaninotto/Faker/issues/1884
     *
     * @param string $absolutePath
     * @param int $width
     * @param int $height
     * @return bool
     */
    protected function saveRandomImage(string $absolutePath, int $width = 640, int $height = 480): bool
    {
        // Create a blank image:
        $im = imagecreatetruecolor($width, $height);
        // Add light background color:
        $bgColor = imagecolorallocate($im, rand(100, 255), rand(100, 255), rand(100, 255));
        imagefill($im, 0, 0, $bgColor);

        // Save the image:
        $isGenerated = imagejpeg($im, $absolutePath);

        // Free up memory:
        imagedestroy($im);

        return $isGenerated;
    }

Proposed PR replaces use of lorempixel.com service, which even while now live is very slow, with placeholder.com service.

@jonathanbossenger we are completely removing the third party implementation in the faker core. See the announcement for 2.x so we are not going to patch this any time soon. Feel free to add a custom provider instead

@pimjansen aha I see, ok no problem.

BTW where would I see announcements :-)

@jonathanbossenger we are completely removing the third party implementation in the faker core. See the announcement for 2.x so we are not going to patch this any time soon. Feel free to add a custom provider instead

why did you make such a decision? we have used this feature in every project and we will need it. It's a burden for us to put something else in place. how can you make such comfortable decisions about the project?

If it's helpful to any one I created an Image Helper which will do the same thing as my initial PR


namespace App\Helpers;

class Image
{

    /**
     * Generate the URL that will return a random image
     *
     * Set randomize to false to remove the random GET parameter at the end of the url.
     *
     * @example 'https://via.placeholder.com/640x480/?12345'
     *
     * @param integer $width
     * @param integer $height
     * @param bool $randomize
     *
     * @return string
     */
    public static function imageUrl($width = 640, $height = 480, $randomize = true): string
    {
        $baseUrl = "https://via.placeholder.com/";
        $url = "{$width}x{$height}/";

        if ($randomize) {
            $url .= '?' . mt_rand();
        }

        return $baseUrl . $url;
    }

    /**
     * Download a remote random image to disk and return its location
     *
     * Requires curl, or allow_url_fopen to be on in php.ini.
     *
     * @param null $dir
     * @param int $width
     * @param int $height
     * @param bool $fullPath
     * @param bool $randomize
     * @return bool|\RuntimeException|string
     * @example '/path/to/dir/13b73edae8443990be1aa8f1a483bc27.jpg'
     */
    public static function image($dir = null, $width = 640, $height = 480, $fullPath = true, $randomize = true)
    {
        $dir = is_null($dir) ? sys_get_temp_dir() : $dir; // GNU/Linux / OS X / Windows compatible
        // Validate directory path
        if (!is_dir($dir) || !is_writable($dir)) {
            throw new \InvalidArgumentException(sprintf('Cannot write to directory "%s"', $dir));
        }

        // Generate a random filename. Use the server address so that a file
        // generated at the same time on a different server won't have a collision.
        $name = md5(uniqid(empty($_SERVER['SERVER_ADDR']) ? '' : $_SERVER['SERVER_ADDR'], true));
        $filename = $name .'.jpg';
        $filepath = $dir . DIRECTORY_SEPARATOR . $filename;

        $url = static::imageUrl($width, $height, $randomize);

        // save file
        if (function_exists('curl_exec')) {
            // use cURL
            $fp = fopen($filepath, 'w');
            $ch = curl_init($url);
            curl_setopt($ch, CURLOPT_FILE, $fp);
            $success = curl_exec($ch) && curl_getinfo($ch, CURLINFO_HTTP_CODE) === 200;
            fclose($fp);
            curl_close($ch);

            if (!$success) {
                unlink($filepath);

                // could not contact the distant URL or HTTP error - fail silently.
                return false;
            }
        } elseif (ini_get('allow_url_fopen')) {
            // use remote fopen() via copy()
            $success = copy($url, $filepath);
        } else {
            return new \RuntimeException('The image formatter downloads an image from a remote HTTP server. Therefore, it requires that PHP can request remote hosts, either via cURL or fopen()');
        }

        return $fullPath ? $filepath : $filename;
    }

}

BTW where would I see announcements :-)

We flagged them under the issues. See #1851

why did you make such a decision? we have used this feature in every project and we will need it. It's a burden for us to put something else in place. how can you make such comfortable decisions about the project?

More info can be found at #1807. In general to summarize it is that we want to bring Faker back to its basics. There are way too many external dependencies at this point. Maintaining all locales is work for someone who understands the locale and not the Faker core itself. Same goes with the images.
To help you guys, it will be very easy extendable so probably you just install a custom faker provider that can generate images for you (whatever service it would be).

I think it's not a problem to remain an optional option.

Maybe a solution for the image problem would be to use different provider (maybe even confiurable in the 'image' method) like
https://picsum.photos/
or
https://loremflickr.com/
?

similiar packages in js have moved away from lorempixel due to downtime issues.

I found this plugin and use it instead of the Core function. Work well with not too much work : https://packagist.org/packages/bheller/images-generator

If someone want fetch images from picsum may use may library: https://github.com/morawskim/faker-images

Due to #1899 I don't created pull request.

If someone want fetch images from picsum may use may library: https://github.com/morawskim/faker-images

Due to #1899 I don't created pull request.

Thanks a lot @morawskim , great job

I solved it this way. I have modified the method imageUrl of the ".../Faker/Provider/Image" class.

  public static function imageUrl($width = 640, $height = 480, $id = null, $randomize = true, $word = null, $gray = false)
    {
        // Example : "https://i.picsum.photos/id/10/200/300.jpg";

        $baseUrl = "https://picsum.photos/";

        // ID Random image
        $url = "id/".$id."/";
        $url .= "{$width}/{$height}/";

        return $baseUrl . $url;
    }

$id will have to be passed as $faker->numberBetween($min = 10, $max = 200);

Thanks everyone for temporary workarounds.

Imo, this should be fixed in 1.0 anyways. I think no one doesn't care what's coming up in 2.0 since it's a future version, not a version coming in a week or so. Also, it's not that hard to just swap providers to fix annoying bug.

I can offer to create a PR, but only if it will not be declined because of "we've plans for 2.0 blah blah blah".

@edgarsn I'm afraid I don't agree with your statement that this should be fixed in 1.0. This is an open source project, and we can't expect open source maintainers to do anything, especially on a project that they maintain in their free time, and for no remuneration.

There are enough work arounds in this issue to provide solutions to folks, or you can fork the software and roll your own solution, but comments like but only if it will not be declined because of "we've plans for 2.0 blah blah blah" are neither helpful or constructive.

@edgarsn I'm afraid I don't agree with your statement that this should be fixed in 1.0. This is an open source project, and we can't expect open source maintainers to do anything, especially on a project that they maintain in their free time, and for no remuneration.

There are enough work arounds in this issue to provide solutions to folks, or you can fork the software and roll your own solution, but comments like but only if it will not be declined because of "we've plans for 2.0 blah blah blah" are neither helpful or constructive.

Then Image class and docs should be removed, don't you think? Imagine if Laravel documentation would describe how to use Request object but in fact it's not working and Taylor would not want to fix it until he releases next major version. Sounds dumb, isn't?

As I said, I can offer a PR, but if the maintainers have a "vision" not to fix this, then at least remove it completetely.

I guess this issue can be closed already as it seems like lorempixel works already without downtime issues. Would be great to change the provider on the fly just by the configuration in the future...

I guess this issue can be closed already as it seems like lorempixel works already without downtime issues. Would be great to change the provider on the fly just by the configuration in the future...

But lorempixel is really slow...

In Russia Lorempixel not working...

I don't understand why they won't just accept a PR to fix this. It's such an easy fix and people are willing to fix it in this version. Right now it's already been another 5 months with this issue going on and lorempixel still working barely (if at all).

Especially given the fact that the devs are deciding to only fix this in 2.0 should be enough reason to at least accept a PR fix for this version too. Any major version upgrade always entails breaking stuff (which is why for certain operating systems LTS versions exist).

xwiz commented

For Laravel, you can replace faker image with UploadedFile::fake()->create('random.extension');.

For those just joining this thread... I ended up using this excellent drop-in library:

https://github.com/salopot/image-generator

Helper

namespace App\Helpers;

/**
 * @see https://github.com/fzaninotto/Faker/issues/1884
 */
class FakerHelper
{
  /**
   * Generate the URL that will return a random image
   *
   * Set randomize to false to remove the random GET parameter at the end of the url.
   *
   * @example 'https://picsum.photos/id/237/200/300'
   *
   * @param integer $width
   * @param integer $height
   * @param string|null $_category NOT USED
   * @param bool $randomize
   * @param string|null $_word NOT USED
   * @param bool $gray
   *
   * @return string
   * @see vendor/fzaninotto/faker/src/Faker/Provider/Image.php > imageUrl
   */
  public static function getImageUrl($width = 640, $height = 480, $_category = null, $randomize = true, $_word = null, $gray = false)
  {
    $baseUrl = 'https://picsum.photos/';
    $url = '';

    if (!$randomize) {
      $url .= 'id/' . rand(1, 1000) . '/';
    }

    $url .= "$width/$height/";

    if ($gray) {
      $url .= '?grayscale';
    }

    if ($randomize) {
      $url .= str_contains($url, '?') ? '&' : '?';
      $url .= 'random=' . rand(1, 1000);
    }

    return $baseUrl . $url;
  }

  public function imageUrl($width = 640, $height = 480, $_category = null, $randomize = true, $_word = null, $gray = false)
  {
    return self::getImageUrl($width, $height, $_category, $randomize, $_word, $gray);
  }

  public static function changeUrl($original_url)
  {
    if (str_starts_with($original_url, 'https://lorempixel.com/')) {
      $o = str_replace('https://lorempixel.com/', '', $original_url);

      $parts = explode('/', $o);
      $width = $parts[0];
      $height = $parts[1];
      $gray = str_contains($original_url, '/gray/');
      $randomize = str_contains($original_url, '?');

      return self::getImageUrl($width, $height, null, $randomize, null, $gray);
    }

    return $original_url;
  }
}

Faker

/** @var \Illuminate\Database\Eloquent\Factory $factory */

use App\Helpers\FakerHelper;

$factory->define('Foo', function () {
  $f = new FakerHelper();
  $height = rand(600, 900);
  $width = intval($height * 2 / 3);

  return [
    // 'logo' => $faker->imageUrl($width, $height, 'NOT USED', false), // Old implementation
    'logo' => $f->imageUrl($width, $height, 'NOT USED', false),
  ];
});

Update

If you want to update your current fake data, you can add a new Migration with following:

$data = MyModel::where([])->get();

foreach ($data as $record) {
  $record->logo = FakerHelper::changeUrl($record->logo);
  $record->save();
}

lorempixel.com is down again, please use something else that is more reliable

lorempixel.com is down.
Replaced following line in \vendor\fzaninotto\faker\src\Faker\Provider\Image.php
//$baseUrl = "https://lorempixel.com/";
with
$baseUrl = "https://picsum.photos/";

and it is working.