Laravel存储SFTP和上传文件权限

8

我正在使用Storage:SFTP (league/flysystem-sftp)将一些文件上传到外部服务器。一切都很顺利,只有一个小问题:文件被上传时的权限为0644 (-rw-r--r--)。我尝试了在put方法中使用文档中的'public'选项,例如:

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

但如果失败了,返回FALSE并且不会上传该文件。

如果我删除'public'参数,一切都很顺利,但文件权限不正确。

是否有方法将上传的文件权限设置为0666之类的值?

6个回答

10
最终的解决方案是将Alpy的答案和配置结合起来。调用 setVisibility() 没有失败,但保留了 0644 权限。深入研究 FTP/SFTP 驱动程序后发现,“public” 权限具有可以使用“permPublic”键在配置中分配的模式,因此在 config/filesystems.php 中编写所需的八进制权限,它按预期工作。
  '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,
    ],

],

];


1
$ftp = Storage::disk('sftp')->put($remote_path, fopen($uploadedFile, 'r+'))->setVisibility($remote_path, 'public'); 我尝试按照你的方式进行操作,同时在filesystems.php中设置了permPublic。但是我遇到了“setVisibility() on boolean”这个问题。 - Azima
请阅读代码,找到标有“this one did the trick”的那一行。 - Carlos Mora

4

文件权限基于两个因素:可见性和权限。您可以在驱动程序配置中设置这两个选项:

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

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

]

权限是根据可见性设置的。因此,如果您设置了 'permPublic' 并且没有设置 'visibility',则什么也不会改变,因为 setVisibility() 函数使用 'visibility' 来获取权限。

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

公共默认值为0755

私有默认值为0700

umask

如果未设置'visibility',我认为权限是基于远程系统用户的umask设置的。如果需要,您可以在远程系统上修改此设置。设置用户的umask

目录

在处理权限时要注意的一点是,这仅会影响到创建的文件。要设置创建的目录的权限,请使用您配置中的'directoryPerm'属性。

此默认值为0744


1
谢谢!我的问题与默认权限有关,它们默认设置为0644。在配置中将它们设置为0755使事情正常工作。你从哪里找到默认值是0755和0700的?对我来说并不是这样运作的,我必须改变它们。 - Carlos Mora

3
这里是一种更加全局和高效的解决方案。我需要在保存递归目录下的文件时控制文件和目录的权限。
League SftpAdapter会递归创建目录,如果不存在的话。但主要问题是它不会为目录添加permPublic => 0755,只会为文件添加,因此如果文件位于新创建的目录中,则www-data用户最终无法访问该文件。解决方法是深入代码查看发生了什么:
'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
    ],
],

League\Flysystem\Sftp\StfpAdapter 中,有两个重要的属性需要清楚地看到:
/**
 * @var array
 */
protected $configurable = ['host', 'hostFingerprint', 'port', 'username', 'password', 'useAgent', 'agent', 'timeout', 'root', 'privateKey', 'passphrase', 'permPrivate', 'permPublic', 'directoryPerm', 'NetSftpConnection'];

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

$configurable 是配置SFTP文件系统驱动的所有可能键。您可以在配置文件中将 directoryPerm0744 更改为 0755

'directoryPerm' => 0755,

不过,由于在StfpAdapter中存在一种类似于Bug的问题https://github.com/thephpleague/flysystem-sftp/issues/81,它不会使用createDir上的$config参数:

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

或者故意将其设置为公共属性:

$filesystem->put('dir1/dir2/'.$filename, $contents, 'public');

1
谢谢!对我来说路径已经给出,所以没有问题,但是在这里得到这个提示很好。 - Carlos Mora

2

我在寻找解决方案时发现了这个,并且在深入研究flysystem代码后,我认为我已经找到了适用于Laravel 9的解决方法。

将以下设置添加到我的配置中似乎起到了作用。

'visibility' => 'public',
'permissions' => [
    'file' => [
        'public' => 0664,
        'private' => 0664,
     ],
     'dir' => [
         'public' => 0775,
         'private' => 0775,
     ],
],

这是适用于 Laravel 9 和 league/flysystem-sftp-v3 包的被接受答案,可以确认它完美地工作,感谢您的努力 @James! - eldorjon
@james-collard 谢谢!我还没有将这个应用程序更新到L9,但它是一个很好的帮助。你介意发布完整的配置参数集吗? - Carlos Mora

0

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


9
请在您的回答中解释这个东西是做什么的。 - General Grievance
3
在这里,解释更多的答案通常会表现得更好。 - M Z

0
请尝试这个:
Storage::disk('remote-sftp')->put($filename, $contents)->setVisibility( $filename, 'public');

假设文件名也包含路径...

谢谢!调用 ->setVisibility($fn, 'public') 返回“true”,但权限仍然相同。 - Carlos Mora
请检查您是否可以使用原始SFTP设置chmod 0666。通常情况下,这应该是可行的。 - Alpy
我试图避免那种方式。拥有如此出色的文件系统抽象,降到那么低的级别似乎太过了。我会尝试查看实现,看看是否有其他方法。 - Carlos Mora
只要排除可能的故障,无需涉及底层操作。setVisibility必须正常工作,以便进行简单的测试。但这肯定是您的决定。 - Alpy
显然在发布 setVisibility() 不起作用之前,我进行了一次测试。看起来是 setVisibility() 使用的属性导致了问题的发生。 - Carlos Mora

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接