8

I'm using Storage:SFTP (league/flysystem-sftp) to upload some files to an external server. Everything goes fine with a small issue: the files are uploaded with a 0644 (-rw-r--r--) permission. I've tried to use 'public' option on the put method as the example from docs, like

Storage::disk('remote-sftp')->put($filename, $contents, 'public');

but if fails returning FALSE and doesn't uploads the file.

If I remove the 'public' parameter, everything goes well but with the wrong permissions for file.

Is there any way to set the uploaded file permissions to something like 0666?

ahmad bd
  • 53
  • 6
Carlos Mora
  • 1,164
  • 2
  • 12
  • 28

6 Answers6

9

Finally the solution was a combination of Alpy's answer and configuration. Calling setVisibility() went without failure, but keep permissions in 0644. Digging into the FTP/SFTP driver found that the 'public' permission has a pattern that can be assigned in config using 'permPublic' key, so writting in config/filesystems.php the desired octal permission it worked as spected.

  'disks' => [

    'local' => [
        'driver' => 'local',
        'root' => storage_path('app'),
    ],

    'public' => [
        'driver' => 'local',
        'root' => storage_path('app/public'),
        'url' => env('APP_URL').'/storage',
        'visibility' => 'public',
    ],

    'remote-sftp' => [
        'driver' => 'sftp',
        'host' => '222.222.222.222',
        'username' => 'myuser',
        'password' => 'mypassword',
        'visibility' => 'public',
        'permPublic' => 0766, /// <- this one did the trick
// 'port' => 22,
        'root' => '/home',
// 'timeout' => 30,
    ],

],

];

Carlos Mora
  • 1,164
  • 2
  • 12
  • 28
  • 1
    `$ftp = Storage::disk('sftp')->put($remote_path, fopen($uploadedFile, 'r+'))->setVisibility($remote_path, 'public');` I tried doing the same as yours.. with `permPublic` set on `filesystems.php`. But I get this `setVisibility() on boolean`. – Azima May 29 '19 at 09:43
  • Please read the code, the line that says "this one did the trick" – Carlos Mora May 30 '19 at 11:01
4

File permissions are based on two factors. Visibility and Permissions. You can set these two options in the driver config as such:

'remote' => [
    'driver' => 'sftp',
    'host' => 'hostname',
    'root' => '/',
    'username' => 'user',
    'password' => env('SYSTEM_PASS'),

    'visibility' => 'public', // defaults to 'private'
    'permPublic' => 0775

]

The permissions are set based on the visibility. So if you set 'permPublic' and don't set 'visibility' nothing will change as, the setVisibility() function uses 'visibility' to get the permissions.

vendor/league/flysystem-sftp/src/SftpAdapter.php

public function setVisibility($path, $visibility)
{
    $visibility = ucfirst($visibility);

    // We're looking for either permPublic or permPrivate
    if (! isset($this->{'perm'.$visibility})) {
        throw new InvalidArgumentException('Unknown visibility: '.$visibility);
    }

    $connection = $this->getConnection();

    return $connection->chmod($this->{'perm'.$visibility}, $path);
}

The public default is 0755.

The private default is 0700.

umask

If 'visibility' is not set, I believe the permissions are set based on the remote system user's umask. You are able to modify this on the remote system, if you so choose. set umask for user

Directories

One thing to note while working with permissions is that this will only affect created files. To set the permissions on created directories, use the 'directoryPerm' attribute in your config.

This defaults to 0744

Beefjeff
  • 371
  • 4
  • 12
  • 1
    Thanks! My problem was related to the default permissions, that by default were set to 0644. Setting them to 0755 in the config made things work. ¿Where did you find that the defaults are 0755 and 0700? that wasn't the way things were working for me, I had to change them. – Carlos Mora Dec 11 '19 at 08:33
3

Here is a more global and efficient solution. I needed to control permission on Files and also directories when saving a file under recursive directories.

League SftpAdapter is creating the directories recursively if not exist yet. But the main problem is that, it won't add the permPublic => 0755 for directories, but only files, hence www-data user end up to have no access to the file if it's inside of a newly created directory. The solution is to dive in the code to see what's happening:

'disks' => [
    'remote-sftp' => [
        'driver' => 'sftp',
        'host' => '222.222.222.222',
        'port' => 22,
        'username' => 'user',
        'password' => 'password',
        'visibility' => 'public', // set to public to use permPublic, or private to use permPrivate
        'permPublic' => 0755, // whatever you want the public permission is, avoid 0777
        'root' => '/path/to/web/directory',
        'timeout' => 30,
        'directoryPerm' => 0755, // whatever you want
    ],
],

In League\Flysystem\Sftp\StfpAdapter, there is 2 important attributes to see clearly:

/**
 * @var array
 */
protected $configurable = ['host', 'hostFingerprint', 'port', 'username', 'password', 'useAgent', 'agent', 'timeout', 'root', 'privateKey', 'passphrase', 'permPrivate', 'permPublic', 'directoryPerm', 'NetSftpConnection'];

/**
 * @var int
 */
protected $directoryPerm = 0744;

The $configurable is all possible keys to configure filesystem sftp driver above. You can change directoryPerm from 0744 to 0755 in config file:

'directoryPerm' => 0755,

HOWEVER, because there is kind a like a Bug in StfpAdapter https://github.com/thephpleague/flysystem-sftp/issues/81 that won't use the $config parameter on createDir:

$filesystem = Storage::disk('remote-sftp');
$filesystem->getDriver()->getAdapter()->setDirectoryPerm(0755);
$filesystem->put('dir1/dir2/'.$filename, $contents);

Or set it with public in purpose:

$filesystem->put('dir1/dir2/'.$filename, $contents, 'public');
KeitelDOG
  • 4,750
  • 4
  • 18
  • 33
2

I found this while looking for a solution and I think I've found what works in Laravel 9 after digging through the flysystem code.

Adding the following settings to my config looks to have done the trick.

'visibility' => 'public',
'permissions' => [
    'file' => [
        'public' => 0664,
        'private' => 0664,
     ],
     'dir' => [
         'public' => 0775,
         'private' => 0775,
     ],
],
Dharman
  • 30,962
  • 25
  • 85
  • 135
  • This is the accepted answer for Laravel 9 and league/flysystem-sftp-v3 package, can confirm it's working seamlessly, thank you for your effort @James! – eldorjon May 31 '22 at 11:16
  • @james-collard Thanks! I haven't updated this app to L9 but it's a great help. Do you mind to post the complete set of config params? – Carlos Mora Dec 27 '22 at 19:25
0

Please try this:

Storage::disk('remote-sftp')->put($filename, $contents)->setVisibility( $filename, 'public');

assuming the filename is also having the path..

Alpy
  • 759
  • 6
  • 9
  • Thanks! Calling ->setVisibility($fn, 'public') returns 'true', but permissions are still the same. – Carlos Mora Mar 28 '19 at 11:19
  • check if you can set the chmod 0666 with raw sftp .. normally this must work – Alpy Mar 28 '19 at 11:46
  • I was trying to avoid to do that way. Having a so great filesystem abstraction, falling down to that low level seems to be too much. I'll try to take a look into the implementation to find out if there is a way. – Carlos Mora Mar 28 '19 at 13:12
  • Nothing about low-level you just eliminate a possible failure due something there. The setVisibility must work so you can make a simple test. But this is sure your call.. – Alpy Mar 28 '19 at 15:05
  • Obviously I made a test before posting setVisibility didn't work. It seems it is the attribute used by setVisibility() the source of the problem. – Carlos Mora Apr 01 '19 at 17:09
0

Storage::disk('sftp')->download(...