在 Laravel 中将会话从文件传输到数据库

2024-03-15

我已经积累了超过6000万个会话,这导致了文件描述符耗尽的情况。 通过将会话传输到数据库解决了该问题。

在 Laravel 5.6 上测试。

为了这:

  1. 准备桌子 https://laravel.com/docs/8.x/session#database

    php artisan 会话:表

    php 工匠迁移

  2. Create Artisan 控制台命令 https://laravel.com/docs/8.x/artisan

在 App\Console\Commands 目录中,创建一个包含以下内容的 SessionMigrate.php 文件:

    <?php
    
    namespace App\Console\Commands;
    
    use Illuminate\Console\Command;
    use Illuminate\Filesystem\Filesystem;
    use Illuminate\Auth\SessionGuard;
    use Illuminate\Support\Facades\DB;
    use Symfony\Component\Console\Helper\ProgressBar;
    
    class SessionMigrate extends Command
    {
        
        protected $signature = 'migrate:sessions';
    
        
        protected $description = 'Migrate sessions from files to database';
    
        protected $files;
        protected $table;
        protected $connection;
    
       
        public function __construct(Filesystem $files)
        {
            parent::__construct();
            $this->files = $files;
            $this->table = config('session.table');
            $this->connection = DB::connection(config('session.connection'));
        }
    
        /**
         * Execute the console command.
         *
         * @return int
         */
        public function handle()
        {
            $this->info("Obtain session files...");
            
            $dir = config('session.files');
            
            $sessions_count = $this->getSessionsCount($dir);
            
            if(FALSE == $dir_res = opendir($dir))
            {
                $this->error("Sessions directory open error.");
                return 1;
            }
            
            
            $lifetime = config('session.lifetime');
            
            $inserted_count = 0;
            $updated_count = 0;
            $errors = 0;
            
            $this->info('Found ' . $sessions_count . ' session files');
            
            $bar = $this->output->createProgressBar($sessions_count);
            $bar->start();
            
        
            while (FALSE !== ($file = readdir($dir_res)))
            {
                $file_path = $dir.'/'.$file;
                
                if (in_array($file, array('.', '..')) || is_dir($file_path))
                { 
                    continue;
                }
                
                $id = $file;
                
                try
                {
                    $content = file_get_contents($file_path);
                    
                    $data = @unserialize($content);
                        
                    if(is_array($data))
                    {
                        $login_name = 'login_web_' . sha1(SessionGuard::class);
                        $user_id = NULL;
                        
                        if(array_key_exists($login_name, $data))
                        {
                            $user_id = $data[$login_name];
                        }
                        
                        $exists = $this->checkExists($id);
                        $last_activity = filemtime($file_path);
                        
                        if($exists)
                        {
                            
                            $this->connection->table($this->table)->whereId($id)->update([
                                'user_id'   => $user_id,
                                'payload'   => base64_encode($content),
                                'last_activity' => $last_activity
                            ]);
                           
                            $updated_count++;
                        }
                        else
                        {   
                            
                            $this->connection->table($this->table)->insert([
                                'id'        => $id,
                                'user_id'   => $user_id,
                                'payload'   => base64_encode($content),
                                'last_activity' => $last_activity
                            ]);
                            
                            $inserted_count++;
                        }
                    
                    }
                }
                catch(Exception $e)
                {
                    $errors++;
                }
                                    
                $bar->advance();
            }
            closedir($dir_res);
            
            
            $bar->finish();
    
            
            $this->table(
                ['Total session files', 'Created', 'Updated', 'Errors'],
                [
                    [$sessions_count, $inserted_count, $updated_count, $errors]
                ]
            );
            
            return 0;
        }
        
        protected function checkExists($id)
        {
            return (bool)$this->connection->table($this->table)->whereId($id)->first();
        }
        
        protected function getSessionsCount(string $dir)
        {
            $result = 0;
            
            if(FALSE == $dir_res = opendir($dir))
            {
                $this->error("Directory open error. ($dir)");
                return 0;
            }
            
            while (($file = readdir($dir_res)) !== false)
            {
                if (!in_array($file, array('.', '..')) && !is_dir($dir.$file))
                { 
                    $result++;
                }
            }
            
            closedir($dir_res);
            
            return $result;
        }
    }
  1. 运行迁移脚本

    php artisan 迁移:会话

  2. 清除 Laravel 配置缓存

    php artisan 配置:缓存

  3. Done.


None

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 Laravel 中将会话从文件传输到数据库 的相关文章

随机推荐