Faker icon indicating copy to clipboard operation
Faker copied to clipboard

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

Open dsampaolo opened this issue 4 years ago • 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.

dsampaolo avatar Jan 09 '20 17:01 dsampaolo

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

DanielSalut avatar Jan 11 '20 21:01 DanielSalut

this service nonsence. 👎 please replace this service with another one.

kvlknctk avatar Jan 13 '20 00:01 kvlknctk

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;
    }

miroslav-demcak-cz avatar Jan 14 '20 12:01 miroslav-demcak-cz

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

jonathanbossenger avatar Jan 16 '20 12:01 jonathanbossenger

@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 avatar Jan 16 '20 12:01 pimjansen

@pimjansen aha I see, ok no problem.

jonathanbossenger avatar Jan 16 '20 12:01 jonathanbossenger

BTW where would I see announcements :-)

jonathanbossenger avatar Jan 16 '20 12:01 jonathanbossenger

@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?

kvlknctk avatar Jan 16 '20 12:01 kvlknctk

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;
    }

}

jonathanbossenger avatar Jan 16 '20 13:01 jonathanbossenger

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).

pimjansen avatar Jan 16 '20 14:01 pimjansen

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

kvlknctk avatar Jan 16 '20 16:01 kvlknctk

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.

PWalkow avatar Jan 23 '20 12:01 PWalkow

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

phenix-factory avatar Jan 30 '20 20:01 phenix-factory

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

Due to https://github.com/fzaninotto/Faker/pull/1899 I don't created pull request.

morawskim avatar Feb 03 '20 17:02 morawskim

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

Lafoiss avatar Feb 04 '20 08:02 Lafoiss

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);

simonemarino avatar Mar 11 '20 15:03 simonemarino

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 avatar Apr 15 '20 14:04 edgarsn

@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.

jonathanbossenger avatar Apr 15 '20 16:04 jonathanbossenger

@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.

edgarsn avatar Apr 15 '20 16:04 edgarsn

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...

PWalkow avatar Apr 18 '20 22:04 PWalkow

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...

poldixd avatar Apr 30 '20 11:04 poldixd

In Russia Lorempixel not working...

Dinver avatar May 11 '20 09:05 Dinver

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).

xorinzor avatar May 22 '20 16:05 xorinzor

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

xwiz avatar Jul 17 '20 11:07 xwiz

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

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

pnoeric avatar Aug 18 '20 15:08 pnoeric

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();
}

reduardo7 avatar Oct 16 '20 16:10 reduardo7

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

stesvis avatar Oct 22 '20 18:10 stesvis

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.

mdutt247 avatar Oct 24 '20 14:10 mdutt247