Visman 2 年 前
コミット
053bfe9b76

+ 2 - 1
.gitignore

@@ -8,8 +8,9 @@
 /app/cache/**/*.tmp
 /app/log/*
 /public/img/avatars/*
+/public/img/og/*
 /public/.htaccess
 /public/index.php
-!.gitkeep
 /public/upload/**/*
 !/public/upload/index.html
+!.gitkeep

+ 10 - 0
app/Core/Image.php

@@ -127,6 +127,16 @@ class Image extends File
         return $result;
     }
 
+    public function width(): int
+    {
+        return $this->imgDriver->width($this->image);
+    }
+
+    public function height(): int
+    {
+        return $this->imgDriver->height($this->image);
+    }
+
     public function __destruct()
     {
         $this->imgDriver->destroy($this->image);

+ 10 - 0
app/Core/Image/DefaultDriver.php

@@ -49,6 +49,16 @@ class DefaultDriver
         return $image;
     }
 
+    public function width(mixed $image): int
+    {
+        return 0;
+    }
+
+    public function height(mixed $image): int
+    {
+        return 0;
+    }
+
     public function destroy(mixed $image): void
     {
     }

+ 10 - 0
app/Core/Image/GDDriver.php

@@ -162,4 +162,14 @@ class GDDriver extends DefaultDriver
 
         return $result;
     }
+
+    public function width(mixed $image): int
+    {
+        return \imagesx($image);
+    }
+
+    public function height(mixed $image): int
+    {
+        return \imagesy($image);
+    }
 }

+ 10 - 0
app/Core/Image/ImagickDriver.php

@@ -123,4 +123,14 @@ class ImagickDriver extends DefaultDriver
             throw new FileException($e->getMessage());
         }
     }
+
+    public function width(mixed $imagick): int
+    {
+        return $imagick->getImageWidth();
+    }
+
+    public function height(mixed $imagick): int
+    {
+        return $imagick->getImageHeight();
+    }
 }

+ 1 - 0
app/Models/Pages/Admin/Install.php

@@ -1582,6 +1582,7 @@ class Install extends Admin
             'b_ant_hidden_ch'         => 1,
             'b_ant_use_js'            => 0,
             's_meta_desc'             => '',
+            'a_og_image'              => \json_encode([], FORK_JSON_ENCODE),
         ];
 
         foreach ($forkConfig as $name => $value) {

+ 81 - 6
app/Models/Pages/Admin/Options.php

@@ -10,6 +10,7 @@ declare(strict_types=1);
 
 namespace ForkBB\Models\Pages\Admin;
 
+use ForkBB\Core\Image;
 use ForkBB\Core\Validator;
 use ForkBB\Models\Page;
 use ForkBB\Models\Pages\Admin;
@@ -114,6 +115,8 @@ class Options extends Admin
                     'b_poll_guest'            => 'required|integer|in:0,1',
                     'b_pm'                    => 'required|integer|in:0,1',
                     'b_oauth_allow'           => 'required|integer|in:0,1',
+                    'upload_og_image'         => 'image',
+                    'delete_og_image'         => 'checkbox',
                 ])->addAliases([
                 ])->addArguments([
                 ])->addMessages([
@@ -122,20 +125,56 @@ class Options extends Admin
                     'o_webmaster_email' => 'Invalid webmaster e-mail message',
                 ]);
 
-            $valid = $v->validation($_POST);
+            $valid = $v->validation($_FILES + $_POST);
             $data  = $v->getData();
 
             if (empty($data['changeSmtpPassword'])) {
                 unset($data['o_smtp_pass']);
             }
 
-            unset($data['changeSmtpPassword'], $data['token']);
+            unset($data['changeSmtpPassword'], $data['token'], $data['upload_og_image'], $data['delete_og_image']);
 
             foreach ($data as $attr => $value) {
                 $config->$attr = $value;
             }
 
             if ($valid) {
+                if (
+                    $v->delete_og_image
+                    || $v->upload_og_image instanceof Image
+                ) {
+                    $folder = $this->c->DIR_PUBLIC . '/img/og/';
+
+                    $this->deleteOgImage($folder);
+
+                    $config->a_og_image = [];
+                }
+
+                if ($v->upload_og_image instanceof Image) {
+                    $path = $folder . $this->c->Secury->randomPass(8) . '.webp';
+
+                    $result = $v->upload_og_image
+                        ->rename(true)
+                        ->rewrite(false)
+                        ->setQuality($this->c->config->i_avatars_quality ?? 75)
+                        ->toFile($path);
+
+                    if (true === $result) {
+                        $config->a_og_image = [
+                            'file'   => $v->upload_og_image->name() . '.' . $v->upload_og_image->ext(),
+                            'width'  => $v->upload_og_image->width(),
+                            'height' => $v->upload_og_image->height(),
+                        ];
+                    } else {
+                        $config->a_og_image = [];
+
+                        $this->c->Log->warning('og:image Failed image processing', [
+                            'user'  => $this->user->fLog(),
+                            'error' => $v->upload_og_image->error(),
+                        ]);
+                    }
+                }
+
                 $config->save();
 
                 return $this->c->Redirect->page('AdminOptions')->message('Options updated redirect', FORK_MESS_SUCC);
@@ -153,6 +192,20 @@ class Options extends Admin
         return $this;
     }
 
+    /**
+     * Удаляет текущую картинку Open Graph
+     */
+    protected function deleteOgImage(string $folder): void
+    {
+        if (! empty($this->c->config->a_og_image['file'])) {
+            $path = $folder . $this->c->config->a_og_image['file'];
+
+            if (\is_file($path)) {
+                \unlink($path);
+            }
+        }
+    }
+
     /**
      * Дополнительная проверка времени online
      */
@@ -202,12 +255,13 @@ class Options extends Admin
     protected function formEdit(Config $config): array
     {
         $form = [
-            'action' => $this->c->Router->link('AdminOptions'),
-            'hidden' => [
+            'action'  => $this->c->Router->link('AdminOptions'),
+            'hidden'  => [
                 'token' => $this->c->Csrf->create('AdminOptions'),
             ],
-            'sets'   => [],
-            'btns'   => [
+            'enctype' => 'multipart/form-data',
+            'sets'    => [],
+            'btns'    => [
                 'save'  => [
                     'type'  => 'submit',
                     'value' => __('Save changes'),
@@ -219,6 +273,10 @@ class Options extends Admin
         $langs  = $this->c->Func->getNameLangs();
         $styles = $this->c->Func->getStyles();
 
+        if (isset($config->a_og_image['file'])) {
+            $this->ogImageUrl = $this->c->PUBLIC_URL . '/img/og/' . $config->a_og_image['file'];
+        }
+
         $form['sets']['essentials'] = [
             'legend' => 'Essentials subhead',
             'fields' => [
@@ -265,6 +323,23 @@ class Options extends Admin
                     'caption' => 'Default style label',
                     'help'    => 'Default style help',
                 ],
+                'a_og_image' => [
+                    'type'    => empty($this->ogImageUrl) ? 'str' : 'yield',
+                    'caption' => 'Og image label',
+                    'value'   => empty($this->ogImageUrl) ? __('Not uploaded') : 'og:image',
+                    'help'    => empty($this->ogImageUrl) ? null : ['Og image help', $config->a_og_image['width'], $config->a_og_image['height']],
+                ],
+                'delete_og_image' => [
+                    'type'    => 'checkbox',
+                    'label'   => 'Delete og image',
+                    'checked' => false,
+                ],
+                'upload_og_image' => [
+                    'type'    => 'file',
+                    'caption' => 'New og image label',
+                    'help'    => 'New og image help',
+                    'accept'  => 'image/*',
+                ],
             ],
         ];
 

+ 1 - 0
app/Models/Pages/Admin/Update.php

@@ -880,6 +880,7 @@ class Update extends Admin
         $config = $this->c->config;
 
         $config->s_meta_desc ??= '';
+        $config->a_og_image  ??= [];
 
         $config->save();
 

+ 18 - 0
app/lang/en/admin_options.po

@@ -452,3 +452,21 @@ msgstr "Meta tag <i>description</i>"
 
 msgid "Meta desc help"
 msgstr "This meta tag can be used by search engines to form a snippet that is displayed in the search results."
+
+msgid "New og image label"
+msgstr "New image"
+
+msgid "New og image help"
+msgstr "Image for Open Graph by default. The recommended size is <b>1200</b> x <b>630</b> pixels."
+
+msgid "Not uploaded"
+msgstr "Not uploaded"
+
+msgid "Og image label"
+msgstr "Image for Open Graph"
+
+msgid "Og image help"
+msgstr "Size is <b>%1$s</b> x <b>%2$s</b> pixels."
+
+msgid "Delete og image"
+msgstr "Delete image for Open Graph"

+ 18 - 0
app/lang/ru/admin_options.po

@@ -452,3 +452,21 @@ msgstr "Мета-тег <i>description</i>"
 
 msgid "Meta desc help"
 msgstr "Данный мета-тег может быть использован поисковыми системами для формирования сниппета, который отображается в результатах поисковой выдачи."
+
+msgid "New og image label"
+msgstr "Новая картинка"
+
+msgid "New og image help"
+msgstr "Картинка для Open Graph по умолчанию. Рекомендуемый размер - <b>1200</b> x <b>630</b> точек."
+
+msgid "Not uploaded"
+msgstr "Не загружена"
+
+msgid "Og image label"
+msgstr "Картинка для Open Graph"
+
+msgid "Og image help"
+msgstr "Pазмер - <b>%1$s</b> x <b>%2$s</b> точек."
+
+msgid "Delete og image"
+msgstr "Удалить картинку для Open Graph"

+ 1 - 0
app/templates/admin/form.forkbb.php

@@ -1,3 +1,4 @@
+@section ('og:image') @if ($p->ogImageUrl) <img class="f-og-img" src="{{ $p->ogImageUrl }}" alt="{{ \basename($p->ogImageUrl) }}"> @endif @endsection
 @extends ('layouts/admin')
       <section class="f-admin @if ($p->classForm) f-{{ \implode('-form f-', $p->classForm) }}-form @endif">
         <h2>{!! __($p->titleForm) !!}</h2>

+ 0 - 0
public/img/og/.gitkeep


+ 8 - 0
public/style/ForkBB/admin.css

@@ -919,6 +919,14 @@
   background-color: #FEEFB3;
 }
 
+/****************************************/
+/* Админка/Опции                        */
+/****************************************/
+#forka .f-og-img {
+  max-width: 100%;
+  max-height: 10rem;
+}
+
 /****************************************/
 /* Админка/Логи                         */
 /****************************************/