我在 Laravel 8 中使用 Flysystem SFTP。我有多个 sftp 帐户,我循环使用每个帐户来制作适配器,然后从服务器读取文件。这一切都是通过控制台命令进行的,并在 Schedule 中注册。问题是,当任何连接由于用户名或密码问题而失败时,它会停止计划任务的执行并跳过剩余的任务。如何检查连接是否成功并继续下一个 sftp 连接。预先感谢。
foreach ($credentials as $cred) {
try {
$driver = Storage::createSFtpDriver($cred);
if($driver->exists('/reports/')) {
//Other code
} else {
continue;
}
} catch (Exception $e) {
continue;
}
}
参见SFTP V3,那里
SftpConnectionProvider
写着:
连接检查器(必须是
的实现,以检查是否可以建立连接(可选,如果不需要一些特殊处理来设置可靠连接,则可以省略)League\Flysystem\PhpseclibV2\ConnectivityChecker
所以答案是
SftpConnectivityChecker implements
ConnectivityChecker
...被传递到 SftpConnectionProvider
构造函数中。 interface
只有一个方法可以重写:
public class SftpConnectivityChecker implements ConnectivityChecker {
public function isConnected(SFTP $connection): bool {
$connected = false
// TODO: inspect the $connection status.
return $connected;
}
}
可能的配置如下:
'sftp' => [
'connectivityChecker' => 'SftpConnectivityChecker'
]
并且不要使用
continue
,而是处理异常而不是忽略它。
我不知道这是否是好方法,但就我而言,它工作正常。我刚刚通过将
\
与 Exception 类一起应用来解决它,并且一切顺利。
foreach($credentials as $cred){
try {
$driver = Storage::createSFtpDriver($cred);
if($driver->exists('/report/')){
echo "Found for ".$cred["username"];
}
else{
continue;
}
}
catch (\Exception $e) {
continue;
}
}
如果你使用flysystem,你需要捕获Throwable。所有 Flysystem 异常实现均扩展自 Throwable。我犯了一个错误,捕获了异常,结果它就直接失败了。
foreach($credentials as $cred){
try {
$driver = Storage::createSFtpDriver($cred);
if($driver->exists('/report/')){
echo "Found for ".$cred["username"];
}
else{
continue;
}
}
catch (\Throwable $e) {
continue;
}
}
另一个问题是,如果您有一个长时间运行的进程,例如由supervisord管理的队列工作进程,那么在作业运行后,工作进程永远不会终止,因此连接永远不会正确断开。您可以通过多种方法来解决此问题,具体取决于您的需求:
使用连接检查器
declare(strict_types=1);
namespace Core\MyConnectivityChecker;
use phpseclib3\Net\SFTP;
use League\Flysystem\PhpseclibV3\ConnectivityChecker;
class MyConnectivityChecker implements ConnectivityChecker
{
public function isConnected(SFTP $connection): bool
{
$connected = $connection->isConnected();
if (!$connected) {
// Ping will check if the connection if active or not. If it's not active it will cleanly
// close the connection and reconnect again.
$connection->ping();
}
return $connection->isConnected();
}
}
另一个选项是在每次使用后显式断开连接:
foreach($credentials as $cred){
try {
$driver = Storage::createSFtpDriver($cred);
if($driver->exists('/report/')){
echo "Found for ".$cred["username"];
}
else{
continue;
}
// force a disconnect
$driver->getAdapter()->getProvideConnection()->disconnect();
}
catch (\Exception $e) {
continue;
}
}