Browse Source

Add avatar upload on registration via OAuth

Visman 2 years ago
parent
commit
947705cc3c
2 changed files with 139 additions and 4 deletions
  1. 120 4
      app/Core/Files.php
  2. 19 0
      app/Models/Pages/RegLog.php

+ 120 - 4
app/Core/Files.php

@@ -45,6 +45,11 @@ class Files
      */
     protected ?DefaultDriver $imageDriver = null;
 
+    /**
+     * Временные файлы
+     */
+    protected array $tmpFiles = [];
+
     /**
      * Список mime типов считающихся картинками
      */
@@ -897,6 +902,14 @@ class Files
         return $this->size($this->maxFileSize, $unit);
     }
 
+    /**
+     * Проверяет путь
+     */
+    public function isBadPath(string $path): bool
+    {
+        return false !== \strpos($path, '//') || \preg_match('%\bphar\b%i', $path);
+    }
+
     /**
      * Переводит объем информации из одних единиц в другие
      * кило = 1024, а не 1000
@@ -1042,7 +1055,7 @@ class Files
     /**
      * Получает один файл из формы
      */
-    protected function uploadFile(array $file): ?File
+    protected function uploadFile(array $file, bool $isUploaded = true): ?File
     {
         if (\UPLOAD_ERR_OK !== $file['error']) {
             switch ($file['error']) {
@@ -1081,7 +1094,10 @@ class Files
             return null;
         }
 
-        if (! \is_uploaded_file($file['tmp_name'])) {
+        if (
+            $isUploaded
+            && ! \is_uploaded_file($file['tmp_name'])
+        ) {
             $this->error = 'The specified file was not uploaded';
 
             return null;
@@ -1147,8 +1163,108 @@ class Files
         return $result;
     }
 
-    public function isBadPath(string $path): bool
+    /**
+     * Получает файл по внешней ссылке
+     */
+    public function uploadFromLink(string $url): ?File
     {
-        return false !== \strpos($path, '//') || \preg_match('%\bphar\b%i', $path);
+        $cmpn = \parse_url($url);
+
+        if (
+            ! isset($cmpn['scheme'], $cmpn['host'], $cmpn['path'])
+            || ! \in_array($cmpn['scheme'], ['https', 'http'], true)
+        ) {
+            $this->error = 'Bad url';
+
+            return null;
+        }
+
+        $tmpName = $this->c->DIR_CACHE . '/' .  $this->c->Secury->randomPass(32) . '.tmp';
+
+        $this->addTmpFile($tmpName);
+
+        $tmpFile = \fopen($tmpName, 'wb');
+
+        if (! $tmpFile) {
+            $this->error = 'Unable to create temporary file for writing';
+
+            return null;
+        }
+
+        if (\extension_loaded('curl')) {
+            $result = $this->curlAction($url, $tmpFile);
+        }
+
+        \fclose($tmpFile);
+
+        if (true === $result) {
+            return $this->uploadFile(
+                [
+                    'tmp_name' => $tmpName,
+                    'name'     => \basename($cmpn['path']) ?: '',
+                    'type'     => '',
+                    'error'    => \UPLOAD_ERR_OK,
+                    'size'     => \filesize($tmpName),
+                ],
+                false
+            );
+        } else {
+            return null;
+        }
+    }
+
+    /**
+     * Загружает файл с помощью cURL
+     */
+    protected function curlAction(string $url, $tmpFile): bool
+    {
+        $ch = \curl_init($url);
+
+        if (! $ch) {
+            $this->error = "Failed cURL init for {$url}";
+
+            return false;
+        }
+
+        \curl_setopt($ch, \CURLOPT_MAXREDIRS, 10);
+        \curl_setopt($ch, \CURLOPT_TIMEOUT, 15);
+        \curl_setopt($ch, \CURLOPT_FILE, $tmpFile);
+        \curl_setopt($ch, \CURLOPT_HTTPGET, true);
+        \curl_setopt($ch, \CURLOPT_HEADER, false);
+
+        $result = \curl_exec($ch);
+
+        \curl_close($ch);
+
+        if (false === $result) {
+            $this->error = 'cURL error: ' . \curl_error($ch);
+
+            return false;
+        } else {
+            return true;
+        }
+    }
+
+    /**
+     * Добавляет путь в список временных файлов для последующего удаления
+     */
+    protected function addTmpFile(string $path): void
+    {
+        $this->tmpFiles[] = $path;
+    }
+
+    /**
+     * Удаляет временные файлы
+     */
+    public function __destruct()
+    {
+        foreach ($this->tmpFiles as $path) {
+            if (
+               ! $this->isBadPath($path)
+               && \is_file($path)
+            ) {
+                \unlink($path);
+            }
+        }
     }
 }

+ 19 - 0
app/Models/Pages/RegLog.php

@@ -10,6 +10,7 @@ declare(strict_types=1);
 
 namespace ForkBB\Models\Pages;
 
+use ForkBB\Core\Image;
 use ForkBB\Models\Page;
 use ForkBB\Models\Provider\Driver;
 use ForkBB\Models\User\User;
@@ -120,6 +121,24 @@ class RegLog extends Page
                 $user->location        = $provider->userLocation;
                 $user->url             = $provider->userURL;
 
+                if ($provider->userAvatar) {
+                    $image = $this->c->Files->uploadFromLink($provider->userAvatar);
+
+                    if ($image instanceof Image) {
+                        $name   = $this->c->Secury->randomPass(8);
+                        $path   = $this->c->DIR_PUBLIC . "{$this->c->config->o_avatars_dir}/{$name}.(webp|jpg|png|gif)";
+                        $result = $image
+                            ->rename(true)
+                            ->rewrite(false)
+                            ->resize($this->c->config->i_avatars_width, $this->c->config->i_avatars_height)
+                            ->toFile($path, $this->c->config->i_avatars_size);
+
+                        if (true === $result) {
+                            $user->avatar = $image->name() . '.' . $image->ext();
+                        }
+                    }
+                }
+
                 $this->c->users->insert($user);
 
                 if (true !== $this->c->providerUser->registration($user, $provider)) {