Image: Intervention/image with Flysystem

Created on 15 Sep 2014  路  17Comments  路  Source: Intervention/image

Hello,

I just discovered Flysystem and learn that it will be integrated into Laravel 5.0. Is it possible to use Flysystem with Intervention/image right now in Larravel 4.2 and how, or do you plan to support it?

Thanks.

All 17 comments

It's possible to use it. You can pass data, read by Flysystem, directly to Intervention Image. To write an image with Flysystem, you need to encode the image first and pass it afterwards.

// read image
$contents = $flysytem->read('foo.jpg');
$image = Image::make($contents);

// write image
$image->encode('png');
$flysytem->put('bar.png', $image);

Great, thanks for your fast reply.

Sorry to bother you again,

the code below works totally fine with the 'local' adapter, but with the 'dropbox' adapter I get this error message:

(images/brides/db/slft82wlrkiivozbkeobgzptifrlsofy.jpg) 'data' has bad type; expecting string, got Intervention\Image\Image

$client = new Client(Config::get('dropbox.token'), Config::get('dropbox.appName'));
$filesystem = new Filesystem(new Dropbox($client, 'public'));
$subdirphoto = 'db';

$files = Input::file('photo');
...
foreach ($files as $fileimg)
...
$newfilename = Str::slug(Str::random(32));
$origfile = file_get_contents($fileimg->getRealPath());
$extension = $fileimg->getClientOriginalExtension();
$dirphoto = Config::get('packages/intervention/image/config.dir_img') . '/' . $subdirphoto;

$photo_dsktp = Image::make($origfile);
$photo_dsktp->resize(Config::get('packages/intervention/image/config.desktop_width'), null, function ($constraint)
{
    $constraint->aspectRatio();
});

try
{
    //$filesystem->put($dirphoto . '/' . $newfilename . '.' . $extension, $origfile);   // this works
    $filesystem->put($dirphoto . '/' . $newfilename . '.' . $extension, $photo_dsktp);   // this doesn't
} catch (Exception $e)
{
    // Problem during the write of a file
    Session::flash('message', '('.$dirphoto . '/' . $newfilename . '.' . $extension.') '.$e->getMessage());
    return Redirect::route('admin.photos.index.dropbox');
}

Notice that if I uncomment, comment the '$filesystem->put' lines to copy the original image ($origfile) it works, so maybe I miss something.

Image needs to be encoded in desired format before you try to save it.

$flysytem->put('foo.png', $image->encode('png'));

Sorry, but it doesn't work.

I had tried that in the resize, like that:

$photo_dsktp->resize(Config::get('packages/intervention/image/config.desktop_width'), null, function ($constraint)
{
    $constraint->aspectRatio();
})->encode('jpg');

to put it in the $filesystem->put doesn't change anything, always the same error message.

Ok, try this with an encoded image.

$flysytem->put('foo.png', (string) $image);

No more error, a file is created in dropbox, but the file is 0 byte.

I put a dd just before, here it is in case it helps:

object(Intervention\Image\Image)[160]
  protected 'driver' => 
    object(Intervention\Image\Gd\Driver)[161]
      public 'decoder' => 
        object(Intervention\Image\Gd\Decoder)[162]
          private 'data' (Intervention\Image\AbstractDecoder) => null
      public 'encoder' => 
        object(Intervention\Image\Gd\Encoder)[163]
          public 'result' => null
          public 'image' => null
          public 'format' => null
          public 'quality' => null
  protected 'core' => resource(185, gd)
  protected 'backup' => null
  public 'encoded' => string '' (length=0)
  public 'mime' => string 'image/jpeg' (length=10)
  public 'dirname' => null
  public 'basename' => null
  public 'extension' => null
  public 'filename' => null

I just tested myself, this works without problems.

use Dropbox\Client;
use League\Flysystem\Filesystem;
use League\Flysystem\Adapter\Dropbox as Adapter;

$client = new Client($token, $appName);
$filesystem = new Filesystem(new Adapter($client, 'path/optional'));

$img = Image::make($filepath);
$img->widen(50);
$img->encode('png');

$d = $filesystem->put('test.png', (string) $img);

Hello @mikeshow , @olivervogel

I seem to be experiencing the same issue. @mikeshow , were you able to figure out what exactly the problem was?

Hello Marlon,

Yes I solved my problem, mainly a semantic one. Here the function to save photos either on dropbox or on local system using flysystem in laravel 4.2 probably works as is in 5.0:

   public function storeFlysystem($sadapter)
   {
      if (Session::token() != Input::get('_token'))
      {
         Session::flash('message', 'Error CSRF');
         return Redirect::route('admin.photos.index', array($sadapter));
      }

      $client = null;
      $filesystem = null;
      $subdirphoto = '';

      if ('DB' == $sadapter)
      {
         $client = new Client(Config::get('dropbox.token'), Config::get('dropbox.appName'));
         $filesystem = new Filesystem(new adaptDropbox($client, 'public'));
         $subdirphoto = 'db';
      }
      elseif ('LC' == $sadapter)
      {
         $client = asset('public');
         $filesystem = new Filesystem(new adapLocal($client));
         $subdirphoto = 'local';
      }

      $files = Input::file('photo');
      if (null != $files[0])
      {
         try
         {
            foreach ($files as $fileimg)
            {
               // --------------------------------------------------------------------
               // Do some checking.
               //
               $imgfilename = '[file: ' . $fileimg->getClientOriginalName() . '] ';

               switch ($fileimg->getError())
               {
                  case UPLOAD_ERR_OK:
                     break;
                  case UPLOAD_ERR_NO_FILE:
                     throw new RuntimeException($imgfilename . 'No file sent.');
                  case UPLOAD_ERR_INI_SIZE:
                  case UPLOAD_ERR_FORM_SIZE:
                     throw new RuntimeException($imgfilename . 'Exceeded System filesize limit.');
                  default:
                     throw new RuntimeException($imgfilename . 'Unknown errors.');
               }

               if ($fileimg->getClientSize() > 1048576)
               {
                  throw new RuntimeException($imgfilename . 'Exceeded filesize limit (>1MB).');
               }

               if ($fileimg->getClientMimeType() != 'image/jpeg')
               {
                  throw new RuntimeException($imgfilename . 'Invalid file format. Must be jpeg.');
               }
               //
               // --------------------------------------------------------------------
               $newfilename = Str::slug(Str::random(32));
               $origfile = $fileimg->getRealPath();
               $extension = $fileimg->getClientOriginalExtension();
               $dirphoto = Config::get('packages/intervention/image/config.dir_img_brides') . '/' . $subdirphoto;

               $photo_dsktp = Image::make($origfile);
               $photo_dsktp->resize(Config::get('packages/intervention/image/config.desktop_width'), null, function ($constraint)
               {
                  $constraint->aspectRatio();
               });
               $photo_dsktp->encode('jpg');

               try
               {
                  $filesystem->put($dirphoto . '/' . $newfilename . '.' . $extension, (string)$photo_dsktp);
               } catch (Exception $e)
               {
                  // Problem during the write of a file
                  Session::flash('message', '(' . $dirphoto . '/' . $newfilename . '.' . $extension . ') ' . $e->getMessage());
                  return Redirect::route('admin.photos.index', array($sadapter));
               }
            }
         } catch (RuntimeException $e)
         {
            // Problem during the read of a file
            Session::flash('message', $e->getMessage());
            return Redirect::route('admin.photos.index', array($sadapter));
         }

         Session::flash('message', 'Add with success!');
         return Redirect::route('admin.photos.index', array($sadapter));
      }
      else
      {
         return Redirect::route('admin.photos.create', array($sadapter))
            ->withInput()
            ->with('message', 'Error file photo.');
      }
   }

As you can see save the photo with a random name (str::random(32)) both for security reason and to avoid funky names sometimes given by users.

Kindly.

Thank you for this! It was causing me all kinds of headaches. It does work in the homestead vm, but within the forge standard deployment it didn't. I wonder if there is an issue with mime detection settings on the standard forge deployment.

Unfortunately I have no experience on this.

@bkschatz @mikeshow

The implementation that worked for me both in homestead and forge is pretty much what @olivervogel suggested.

From what I have seen this line is important Flysystem::put($upload_path, (string) $image); as it casts the Image created by InterventionImage to string during the actual upload.

It also worked using it as Flysystem::put($upload_path, $image->_toString());

Hope this helps.

 public function upload($file)
 {
        $filename = strtolower(str_random(40)) . '.' . $file->getClientOriginalExtension();

        $image = Image::make($file)
                        ->encode($file->getClientOriginalExtension())
                        ->save();

        try
        {
            $upload_path = getenv('UPLOAD_DIRECTORY') . $filename;

            Flysystem::put($upload_path, (string) $image);
        }
        catch (Exception $ex)
        {
            return 'Upload failed';
        }

        return $filename;
 }

@marlongichie
It did work for me. I was just saying that it works without (string) on my vm (laravel/homestead), but it doesn't in production. I was looking at the errors and it stemmed from a mime detection problem on the production system. So there is some configuration or outdated package that is throwing that error.

Thanks for the help!

Brandon

Hello,

I'm having similar issue with the ->writeStream() method on Flysystem. I previously used the ->encode() method too on Intervention/Image, but since it needs a stream I used this instead:

$image = $image->stream(pathinfo($path, PATHINFO_EXTENSION));

$this->filesystem->disk($this->getConfiguredFilesystem())->writeStream($filename, $image, [
    'visibility' => 'public',
    'mimetype' => 'image/png',
]);

Issue with this is that writeStream requires a resource, ie I'm getting this error:

League\Flysystem\Filesystem::writeStream expects argument #2 to be a valid resource.

While the ->stream() method returns an instance of GuzzleHttp\Psr7\Stream.

Any ideas how I could get an actual resource ?

Thank you

@nWidart you can get the resource by calling the detach method on the GuzzleHttp\Psr7\Stream response.

That works, thank you very much! :smile:

Was this page helpful?
0 / 5 - 0 ratings

Related issues

txusramone picture txusramone  路  6Comments

kamov picture kamov  路  6Comments

p4bloch picture p4bloch  路  6Comments

bkkrishna picture bkkrishna  路  7Comments

REPTILEHAUS picture REPTILEHAUS  路  5Comments