[3.2][3.3] Вставка картинок
Правила форума
Местная Конституция | Шаблон запроса | Документация (phpBB3) | Мини [FAQ] по phpBB3.1.x/3.3.x | FAQ | Как задавать вопросы | Как устанавливать расширения
Ваш вопрос может быть удален без объяснения причин, если на него есть ответы по приведённым ссылкам (а вы рискуете получить предупреждение
).
Местная Конституция | Шаблон запроса | Документация (phpBB3) | Мини [FAQ] по phpBB3.1.x/3.3.x | FAQ | Как задавать вопросы | Как устанавливать расширения
Ваш вопрос может быть удален без объяснения причин, если на него есть ответы по приведённым ссылкам (а вы рискуете получить предупреждение
-
Siava
- Поддержка

- Сообщения: 5557
- Стаж: 21 год 8 месяцев
- Откуда: Питер
- Благодарил (а): 187 раз
- Поблагодарили: 776 раз
Re: [3.2][3.3] Вставка картинок
Михаил Молчанов, добавьте в админке это расширение и будет поддерживать.
Еще одно нарушение правил и будете забанены. © Mr. Anderson
Ты очистил кеш? © Sheer
https://siava.ru (phpbb2.0.x 3.5.x)
Ты очистил кеш? © Sheer
https://siava.ru (phpbb
-
Michel
- Поддержка

- Сообщения: 650
- Стаж: 14 лет 8 месяцев
- Откуда: Липецк
- Благодарил (а): 144 раза
- Поблагодарили: 81 раз
Re: [3.2][3.3] Вставка картинок
По умолчанию не поддерживает. Но можно попробовать форум заставить поддерживать данный формат. Вопрос зачем? Ведь формат jfif является тем же самым jpeg. Можно изменить окончание файла на jpg и форум его примет как родного.
-
Михаил Молчанов
- phpBB 1.4.4
- Сообщения: 181
- Стаж: 2 года 1 месяц
- Откуда: Москва
- Благодарил (а): 3 раза
- Поблагодарили: 7 раз
-
Michel
- Поддержка

- Сообщения: 650
- Стаж: 14 лет 8 месяцев
- Откуда: Липецк
- Благодарил (а): 144 раза
- Поблагодарили: 81 раз
Re: [3.2][3.3] Вставка картинок
В движке phpBB встроена строгая система безопасности, которая сверяет реальный тип файла с его расширением. Для системы расширение .jfif является неизвестным "чужаком", хотя внутри находится стандартный MIME-тип image/jpeg. Чтобы подружить phpBB с форматом .jfif, нужно выполнить два шага: один в панели администратора, а второй — в коде самого форума.Siava писал(а): 19.09.2026 0:08 Михаил Молчанов, добавьте в админке это расширение и будет поддерживать.
Если просто добавить формат в админке, то при загрузке мы получим ошибку "Несовпадение типа изображения: ожидаемое расширение jpg вместо полученного jfif."
Отправлено спустя 25 минут 26 секунд:
Измените окончание файла с jfif на jpg и всё.Михаил Молчанов писал(а): 19.09.2026 0:37 У меня jfif добавлено через админку. но всё равно не поддерживается
Так как:
Менять код движка не рекомендуется!!!
Отправлено спустя 9 минут 15 секунд:
Но если сильно хочется, то нужно отредактировать файл
Код: Выделить всё
phpbb/files/upload.phpКод: Выделить всё
IMAGETYPE_JPEG => ['jpg', 'jpeg'],Код: Выделить всё
IMAGETYPE_JPEG => ['jpg', 'jpeg', 'jfif'],-
rxu
- phpBB Guru

- Сообщения: 17256
- Стаж: 20 лет 4 месяца
- Откуда: Красноярск
- Благодарил (а): 587 раз
- Поблагодарили: 1783 раза
Re: [3.2][3.3] Вставка картинок
Оно же, но надо проверять на работоспособность.
Re: [3.1][3.2] BB3ImageUpload: загрузка изображений на внешние хостинги изображений
-
Kuskow
- phpBB 2.0.6
- Сообщения: 513
- Стаж: 10 лет 3 месяца
- Откуда: 🇰🇿 Караганда
- Благодарил (а): 30 раз
- Поблагодарили: 48 раз
Re: [3.2][3.3] Вставка картинок
Что-то пользователи без энтузиазма восприняли нововведение. Некоторые сказали, что им недостаточно выбирать файлы, нужен копипаст (перетаскивать выбранные файлы из проводника в окно загрузки понравилось). Но мы с Google-ИИ не стали это реализовывать, а пошли чуть дальше и сделали копипаст изображения прямо в текст сообщения. Теперь можно, например, сделать скриншот и вставить его в своё сообщение, не сохраняя на локальном диске. Или, листая свой web-фотоальбом, скопировать оттуда изображение и вставить в окно редактирования сообщения на форуме. Ну и в проводнике можно выбрать несколько локальных файлов, скопировать список и вставить их прямо в сообщение - файлы загрузятся на сервер, а в окне редактирования появятся ссылки на загруженные файлы, обрамлённые тегами img. Красота красивая!
Кому надо так же, измените код в этом файле. Не забудьте вместо контекста "ЗАМЕНИТЬ_ТОКЕН" подставить своё, что у вас там, чтобы было одинаково со вторым файлом.
Кому надо так же, измените код в этом файле. Не забудьте вместо контекста "ЗАМЕНИТЬ_ТОКЕН" подставить своё, что у вас там, чтобы было одинаково со вторым файлом.
Kuskow писал(а): 18.09.2026 5:43В папке шаблона
/styles/prosilver/templateсоздаём файлfast_upload.jsи записываем в него код:
Код: Выделить всё
(function() {
let globalFileInput = null;
const SECRET_TOKEN = 'ЗАМЕНИТЬ_ТОКЕН';
const ORIGINAL_ICON = '<i class="icon fa-cloud-upload fa-fw" aria-hidden="true"></i>';
function getOrCreateFileInput() {
if (globalFileInput) return globalFileInput;
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.id = 'fast-image-file-input';
fileInput.multiple = true;
fileInput.accept = 'image/*';
fileInput.style.display = 'none';
document.body.appendChild(fileInput);
globalFileInput = fileInput;
return fileInput;
}
// Универсальная функция для отправки файлов на сервер и вставки BB-кодов
function uploadAndInsertImages(files, newButton, statusSpan, textarea) {
if (!files || files.length === 0) return;
const formData = new FormData();
formData.append('token', SECRET_TOKEN);
for (let i = 0; i < files.length; i++) {
formData.append('images[]', files[i]);
}
// Анимация на кнопке
if (newButton) {
newButton.innerHTML = '⏳';
newButton.disabled = true;
}
if (statusSpan) statusSpan.textContent = '⏳';
fetch('/upload_compress.php', {
method: 'POST',
body: formData
})
.then(response => {
if (!response.ok) throw new Error('Ошибка сервера ' + response.status);
return response.json();
})
.then(data => {
if (data.links && data.links.length > 0) {
const startPos = textarea.selectionStart;
const endPos = textarea.selectionEnd;
const hasTextBefore = textarea.value.substring(0, startPos).trim().length > 0;
let bbcodeInsert = hasTextBefore ? '\r\n\r\n' : '';
data.links.forEach((link, index) => {
bbcodeInsert += `[img]${link}[/img]`;
if (index < data.links.length - 1) {
bbcodeInsert += '\r\n\r\n\r\n';
}
});
bbcodeInsert += '\r\n\r\n';
const textBefore = textarea.value.substring(0, startPos);
const textAfter = textarea.value.substring(endPos, textarea.value.length);
textarea.value = textBefore + bbcodeInsert + textAfter;
textarea.focus();
textarea.selectionStart = textarea.selectionEnd = startPos + bbcodeInsert.length;
if (newButton) newButton.innerHTML = '✅';
if (statusSpan) statusSpan.textContent = '✅';
} else {
if (newButton) newButton.innerHTML = '❌';
if (statusSpan) statusSpan.textContent = '❌';
}
})
.catch(error => {
console.error('Ошибка:', error.message);
if (newButton) newButton.innerHTML = '❌';
if (statusSpan) statusSpan.textContent = '❌';
})
.finally(() => {
setTimeout(() => {
if (newButton) {
newButton.innerHTML = ORIGINAL_ICON;
newButton.disabled = false;
}
if (statusSpan) statusSpan.textContent = '';
}, 2500);
});
}
function injectUploadButton(colorButton, textarea) {
if (!colorButton || !textarea || colorButton.parentNode.querySelector('.phpbb-fast-upload-trigger')) return;
const newButton = document.createElement('button');
newButton.type = 'button';
newButton.className = 'button button-icon-only phpbb-fast-upload-trigger';
newButton.title = 'Загрузить фото';
newButton.innerHTML = ORIGINAL_ICON;
newButton.style.marginLeft = '4px';
colorButton.parentNode.insertBefore(newButton, colorButton.nextSibling);
// Клик по кнопке (обычный выбор файлов с диска)
newButton.onclick = function(e) {
e.preventDefault();
e.stopPropagation();
const fileInput = getOrCreateFileInput();
fileInput.onchange = null;
fileInput.onchange = function() {
if (!fileInput.files || fileInput.files.length === 0) return;
uploadAndInsertImages(fileInput.files, newButton, null, textarea);
fileInput.value = '';
};
fileInput.click();
};
// НАЧАЛО БЛОКА КОПИПАСТА (Ctrl+V)
// Вешаем слушатель события вставки прямо на текстовое поле ввода сообщения
textarea.addEventListener('paste', function(e) {
// Проверяем, есть ли бинарные данные (файлы) в буфере обмена
if (!e.clipboardData || !e.clipboardData.files || e.clipboardData.files.length === 0) {
return; // Если вставили обычный текст — ничего не делаем, работает стандартно
}
const pastedFiles = [];
for (let i = 0; i < e.clipboardData.files.length; i++) {
const file = e.clipboardData.files[i];
// Нам нужны только изображения
if (file.type.indexOf('image/') !== -1) {
pastedFiles.push(file);
}
}
if (pastedFiles.length > 0) {
// Предотвращаем стандартное поведение браузера (чтобы в textarea не вставился мусор)
e.preventDefault();
// Запускаем процесс отправки скопированных картинок
uploadAndInsertImages(pastedFiles, newButton, null, textarea);
}
});
// КОНЕЦ БЛОКА КОПИПАСТА
}
function autoScanAndInject() {
const colorButtons = document.querySelectorAll('[name="bbpalette"], #bbpalette, .bbcode-color');
if (colorButtons.length > 0) {
colorButtons.forEach(colorBtn => {
const parentForm = colorBtn.closest('form') || colorBtn.closest('.quickreply') || colorBtn.closest('#qr_postform') || document;
const textarea = parentForm.querySelector('textarea');
if (textarea) {
injectUploadButton(colorBtn, textarea);
}
});
}
}
autoScanAndInject();
const observer = new MutationObserver(() => autoScanAndInject());
observer.observe(document.body, { childList: true, subtree: true });
})();
-
Evangelion
- phpBB 2.0.5
- Сообщения: 478
- Стаж: 14 лет 9 месяцев
- Благодарил (а): 58 раз
- Поблагодарили: 104 раза
Re: [3.2][3.3] Вставка картинок
Kuskow, имеется расширения для вставки изображений из буфера обмена https://www.phpbb.com/customise/db/exte ... oardimage/
-
Kuskow
- phpBB 2.0.6
- Сообщения: 513
- Стаж: 10 лет 3 месяца
- Откуда: 🇰🇿 Караганда
- Благодарил (а): 30 раз
- Поблагодарили: 48 раз
Re: [3.2][3.3] Вставка картинок
Я не хочу пользоваться вложениями. Это крайне неудобно. А конкретно на этом сайте phpBBguru ещё и часто глючно. Мне тут приходится перезаливать вложения каждый раз при редактировании сообщения. Нельзя выбрать и загрузить сразу несколько файлов и т.д.
К тому же, вложения не изменяют я в размере. Ну и когда всё это отдельно начинаешь думать-собирать, получается совсем неприлично. А тут простейшие решение очень лёгкое само по себе и не требует много ресурсов.
Когда (если) попробуете, как оно работает, уже не захочется возвращаться к вложениям.
К тому же, вложения не изменяют я в размере. Ну и когда всё это отдельно начинаешь думать-собирать, получается совсем неприлично. А тут простейшие решение очень лёгкое само по себе и не требует много ресурсов.
Когда (если) попробуете, как оно работает, уже не захочется возвращаться к вложениям.
-
Татьяна5
- Поддержка

- Сообщения: 13153
- Стаж: 15 лет 1 месяц
- Благодарил (а): 167 раз
- Поблагодарили: 2397 раз
Re: [3.2][3.3] Вставка картинок
Зачем?Kuskow писал(а): Вчера 11:54 Мне тут приходится перезаливать вложения каждый раз при редактировании сообщения
У меня без перезаливки всё работает как надо
Можно, несколькими способами
Изменяются, если это картинки
-
Kuskow
- phpBB 2.0.6
- Сообщения: 513
- Стаж: 10 лет 3 месяца
- Откуда: 🇰🇿 Караганда
- Благодарил (а): 30 раз
- Поблагодарили: 48 раз
Re: [3.2][3.3] Вставка картинок
Ну вот у меня без перезаливки не получается отредактировать сообщение здесь - вложение исчезает. Наверное, браузер у меня такой странный. Но я не жалуюсь - понимаю, что такое бывает, мне не сложно, да и не часто я тут вложения вкладываю.
-
Kuskow
- phpBB 2.0.6
- Сообщения: 513
- Стаж: 10 лет 3 месяца
- Откуда: 🇰🇿 Караганда
- Благодарил (а): 30 раз
- Поблагодарили: 48 раз
Re: [3.2][3.3] Вставка картинок
После успешного тестирования первой версии мы с Google-ИИ посовещались и решили, что сжатие и перекодирование файлов нужно делать на стороне клиента, чтобы в путешествиях экономить трафик и скорость на мобильном интернете. Поэтому вот вторая версия быстрого загрузчика фотографий и других изображений на форум. И ещё добавили авторизацию по сессии, так что, больше никаких токенов.
Рядом с кнопкой IMG появляется ещё одна кнопка с нарисованным облачком и стрелочкой, означающая загрузку фотофайлов. Файлы можно выбрать из списка, который появляется при нажатии на кнопку или скопировать в окно редактирования сообщения. Так же можно скопировать не файл, а изображение прям в окно редактирования, оно превратится в файл на сервере.
Все загружаемые изображения преобразуются в JPEG, из них вырезается весь EXIF, после чего они сжимаются до 1024 пикселей (по ширине или высоте) и сохраняются в папку
Как установить на своём форуме:
В корневой папке форума создаём папку
В корневой папке форума создаём файл
В папке шаблона
В той же папке шаблона
Заходим в админку форума: Общие - Очистить кэш.
Рядом с кнопкой IMG появляется ещё одна кнопка с нарисованным облачком и стрелочкой, означающая загрузку фотофайлов. Файлы можно выбрать из списка, который появляется при нажатии на кнопку или скопировать в окно редактирования сообщения. Так же можно скопировать не файл, а изображение прям в окно редактирования, оно превратится в файл на сервере.
Все загружаемые изображения преобразуются в JPEG, из них вырезается весь EXIF, после чего они сжимаются до 1024 пикселей (по ширине или высоте) и сохраняются в папку
/img/, где раскладываются в подпапки по месяцам. После загрузки в текст сообщения сразу вставляется ссылка на изображение, обрамлённая тегами [img][/img].Как установить на своём форуме:
/img с правами 755 или 777.upload_compress.php и записываем в него код:
Код: Выделить всё
<?php
### phpBB Image Download v2.0 by Kuskow & AI on Google Search
// --- БЛОК НАСТРОЕК СЕРВЕРА ---
define('MAX_WIDTH', 1024); // Максимальная ширина из JS
define('MAX_HEIGHT', 1024); // Максимальная высота из JS
define('GABARIT_MARGIN', 5); // Разрешенный допуск в пикселях (+5)
// -----------------------------
header('Content-Type: application/json');
header('Access-Control-Allow-Origin: *');
$phpbb_root_path = './';
$base_upload_dir = 'img/';
$uploaded_links = [];
// 1. Читаем настройки подключения к базе данных напрямую из config.php
if (!file_exists($phpbb_root_path . 'config.php')) {
http_response_code(500);
echo json_encode(['error' => 'Конфигурационный файл не найден']);
exit;
}
@include($phpbb_root_path . 'config.php');
if (!isset($dbhost) || !isset($dbname) || !isset($dbuser) || !isset($dbpasswd)) {
http_response_code(500);
echo json_encode(['error' => 'Не удалось прочитать конфигурацию базы данных']);
exit;
}
// 2. Ищем куку сессии phpBB по суффиксу '_sid'
$sid = '';
foreach ($_COOKIE as $key => $value) {
if (substr($key, -4) === '_sid') {
$sid = preg_replace('/[^a-zA-Z0-9]/', '', $value);
break;
}
}
if (empty($sid)) {
http_response_code(403);
echo json_encode(['error' => 'Доступ запрещен: авторизация не найдена']);
exit;
}
// 3. Подключаемся к базе данных через родной mysqli
$port = isset($dbport) ? (int)$dbport : 3306;
$mysqli = @new mysqli($dbhost, $dbuser, $dbpasswd, $dbname, $port);
if ($mysqli->connect_error) {
http_response_code(500);
echo json_encode(['error' => 'Ошибка подключения к базе данных']);
exit;
}
$mysqli->set_charset("utf8mb4");
// 4. Проверяем сессию в таблице phpBB.
$session_table = $table_prefix . 'sessions';
$safe_sid = $mysqli->real_escape_string($sid);
$query = "SELECT session_user_id FROM {$session_table} WHERE session_id = '{$safe_sid}' AND session_user_id <> 1 LIMIT 1";
$result = $mysqli->query($query);
if (!$result || $result->num_rows === 0) {
$mysqli->close();
http_response_code(403);
echo json_encode(['error' => 'Доступ запрещен: сессия недействительна']);
exit;
}
$mysqli->close();
// --- НАДЕЖНАЯ ПРОВЕРКА ФАЙЛОВ-ФАЕРВОЛ ---
if (empty($_FILES['images']['name'])) {
http_response_code(400);
echo json_encode(['error' => 'Файлы не получены']);
exit;
}
// Создаем подпапку года/месяца
$sub_dir = date('Ym') . '/';
$target_dir = $base_upload_dir . $sub_dir;
if (!is_dir($target_dir)) {
@mkdir($target_dir, 0755, true);
}
foreach ($_FILES['images']['tmp_name'] as $key => $tmp_name) {
if (empty($tmp_name)) continue;
$orig_name = $_FILES['images']['name'][$key];
$file_size = $_FILES['images']['size'][$key];
// Лимит веса в 1.5 МБ
if ($file_size > 1.5 * 1024 * 1024) {
continue;
}
// Проверка структуры файла (защита от вирусов)
$image_info = @getimagesize($tmp_name);
if (!$image_info) {
continue;
}
list($width, $height, $type) = $image_info;
// Жесткий лимит пикселей из констант (1024 + 5 = 1029px)
if ($width > (MAX_WIDTH + GABARIT_MARGIN) || $height > (MAX_HEIGHT + GABARIT_MARGIN)) {
continue;
}
if ($type !== IMAGETYPE_JPEG) {
continue;
}
// Формируем чистое оригинальное имя файла
$original_name_clean = pathinfo($orig_name, PATHINFO_FILENAME);
$original_name_clean = preg_replace('/[^a-zA-Z0-9а-яА-ЯёЁ_\-\.]/u', '', $original_name_clean);
// Возвращаем надежный уникальный маркер времени (base36 от микросекунд)
$short_prefix = base_convert(str_replace('.', '', microtime(true)), 10, 36);
// Имя файла: маркер_исходноеимя.jpg (например, 6ceohoq4w_IMG_20260920_120817.jpg)
$file_name = $short_prefix . '_' . $original_name_clean . '.jpg';
$target_file = $target_dir . $file_name;
// Мгновенное безопасное перемещение файла без риска перезаписи
$success = @move_uploaded_file($tmp_name, $target_file);
if ($success) {
$protocol = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https://' : 'http://';
$full_url = $protocol . $_SERVER['HTTP_HOST'] . '/' . $target_file;
$uploaded_links[] = $full_url;
}
}
echo json_encode(['links' => $uploaded_links]);
exit;
/styles/prosilver/template создаём файл fast_upload.js и записываем в него код:
Код: Выделить всё
// phpBB Image Download v2.0 by Kuskow & AI on Google Search
(function() {
let globalFileInput = null;
const ORIGINAL_ICON = '<i class="icon fa-cloud-upload fa-fw" aria-hidden="true"></i>';
const MAX_WIDTH = 1024;
const MAX_HEIGHT = 1024;
const QUALITY = 0.83;
function getOrCreateFileInput() {
if (globalFileInput) return globalFileInput;
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.id = 'fast-image-file-input';
fileInput.multiple = true;
fileInput.accept = 'image/*';
fileInput.style.display = 'none';
document.body.appendChild(fileInput);
globalFileInput = fileInput;
return fileInput;
}
// Функция тотального сжатия картинки через Canvas
function compressImageClientSide(file) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(event) {
const img = new Image();
img.src = event.target.result;
img.onload = function() {
let width = img.width;
let height = img.height;
const ratio = Math.min(MAX_WIDTH / width, MAX_HEIGHT / height);
if (ratio < 1) {
width = Math.round(width * ratio);
height = Math.round(height * ratio);
}
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#FFFFFF';
ctx.fillRect(0, 0, width, height);
ctx.drawImage(img, 0, 0, width, height);
canvas.toBlob(function(blob) {
let origName = file.name || 'pasted_image.png';
let lastDot = origName.lastIndexOf('.');
let baseName = lastDot !== -1 ? origName.substring(0, lastDot) : origName;
let newFileName = baseName + '.jpg';
const compressedFile = new File([blob], newFileName, {
type: 'image/jpeg',
lastModified: Date.now()
});
resolve(compressedFile);
}, 'image/jpeg', QUALITY);
};
};
});
}
function uploadAndInsertImages(files, textarea) {
if (!files || files.length === 0) return;
const compressionPromises = Array.from(files).map(file => compressImageClientSide(file));
Promise.all(compressionPromises).then(compressedFiles => {
const formData = new FormData();
// Чистая отправка: только массив сжатых файлов, куки сессии браузер прикрепит сам
compressedFiles.forEach(file => {
formData.append('images[]', file);
});
return fetch('/upload_compress.php', {
method: 'POST',
body: formData
});
})
.then(response => {
if (!response.ok) throw new Error('Ошибка сервера ' + response.status);
return response.json();
})
.then(data => {
if (data.links && data.links.length > 0) {
const startPos = textarea.selectionStart;
const endPos = textarea.selectionEnd;
const hasTextBefore = textarea.value.substring(0, startPos).trim().length > 0;
let bbcodeInsert = hasTextBefore ? '\r\n\r\n' : '';
data.links.forEach((link, index) => {
bbcodeInsert += `[img]${link}[/img]`;
if (index < data.links.length - 1) {
bbcodeInsert += '\r\n\r\n\r\n';
}
});
bbcodeInsert += '\r\n\r\n';
const textBefore = textarea.value.substring(0, startPos);
const textAfter = textarea.value.substring(endPos, textarea.value.length);
textarea.value = textBefore + bbcodeInsert + textAfter;
textarea.focus();
textarea.selectionStart = textarea.selectionEnd = startPos + bbcodeInsert.length;
}
})
.catch(error => {
console.error('Ошибка при загрузке:', error.message);
})
.finally(() => {
if (globalFileInput) globalFileInput.value = '';
});
}
function injectUploadButton(colorButton, textarea) {
if (!colorButton || !textarea || colorButton.parentNode.querySelector('.phpbb-fast-upload-trigger')) return;
const newButton = document.createElement('button');
newButton.type = 'button';
newButton.className = 'button button-icon-only phpbb-fast-upload-trigger';
newButton.title = 'Загрузить фото';
newButton.innerHTML = ORIGINAL_ICON;
newButton.style.marginLeft = '4px';
colorButton.parentNode.insertBefore(newButton, colorButton.nextSibling);
newButton.onclick = function(e) {
e.preventDefault();
e.stopPropagation();
const fileInput = getOrCreateFileInput();
fileInput.onchange = null;
fileInput.onchange = function() {
if (!fileInput.files || fileInput.files.length === 0) return;
uploadAndInsertImages(fileInput.files, textarea);
};
fileInput.click();
};
textarea.addEventListener('paste', function(e) {
if (!e.clipboardData || !e.clipboardData.files || e.clipboardData.files.length === 0) {
return;
}
const pastedFiles = [];
for (let i = 0; i < e.clipboardData.files.length; i++) {
const file = e.clipboardData.files[i];
if (file.type.indexOf('image/') !== -1) {
pastedFiles.push(file);
}
}
if (pastedFiles.length > 0) {
e.preventDefault();
uploadAndInsertImages(pastedFiles, textarea);
}
});
}
function autoScanAndInject() {
const imgButtons = document.querySelectorAll('[name="addbbcode16"], .bbcode-img');
if (imgButtons.length > 0) {
imgButtons.forEach(imgBtn => {
const parentForm = imgBtn.closest('form') || imgBtn.closest('.quickreply') || imgBtn.closest('#qr_postform') || document;
const textarea = parentForm.querySelector('textarea');
if (textarea) {
// Передаем кнопку IMG в качестве ориентира для вставки
injectUploadButton(imgBtn, textarea);
}
});
}
}
autoScanAndInject();
const observer = new MutationObserver(() => autoScanAndInject());
observer.observe(document.body, { childList: true, subtree: true });
})();
(function() {
let globalFileInput = null;
const SECRET_TOKEN = 'NavimbaFastImageUploadKey2026';
const ORIGINAL_ICON = '<i class="icon fa-cloud-upload fa-fw" aria-hidden="true"></i>';
const MAX_WIDTH = 1024;
const MAX_HEIGHT = 1024;
const QUALITY = 0.83;
function getOrCreateFileInput() {
if (globalFileInput) return globalFileInput;
const fileInput = document.createElement('input');
fileInput.type = 'file';
fileInput.id = 'fast-image-file-input';
fileInput.multiple = true;
fileInput.accept = 'image/*';
fileInput.style.display = 'none';
document.body.appendChild(fileInput);
globalFileInput = fileInput;
return fileInput;
}
// Функция тотального сжатия картинки через Canvas (без логов в консоль)
function compressImageClientSide(file) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.readAsDataURL(file);
reader.onload = function(event) {
const img = new Image();
img.src = event.target.result;
img.onload = function() {
let width = img.width;
let height = img.height;
const ratio = Math.min(MAX_WIDTH / width, MAX_HEIGHT / height);
if (ratio < 1) {
width = Math.round(width * ratio);
height = Math.round(height * ratio);
}
const canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
const ctx = canvas.getContext('2d');
ctx.fillStyle = '#FFFFFF';
ctx.fillRect(0, 0, width, height);
ctx.drawImage(img, 0, 0, width, height);
canvas.toBlob(function(blob) {
let origName = file.name || 'pasted_image.png';
let lastDot = origName.lastIndexOf('.');
let baseName = lastDot !== -1 ? origName.substring(0, lastDot) : origName;
let newFileName = baseName + '.jpg';
const compressedFile = new File([blob], newFileName, {
type: 'image/jpeg',
lastModified: Date.now()
});
resolve(compressedFile);
}, 'image/jpeg', QUALITY);
};
};
});
}
function uploadAndInsertImages(files, textarea) {
if (!files || files.length === 0) return;
const compressionPromises = Array.from(files).map(file => compressImageClientSide(file));
Promise.all(compressionPromises).then(compressedFiles => {
const formData = new FormData();
formData.append('token', SECRET_TOKEN);
compressedFiles.forEach(file => {
formData.append('images[]', file);
});
return fetch('/upload_compress.php', {
method: 'POST',
body: formData
});
})
.then(response => {
if (!response.ok) throw new Error('Ошибка сервера ' + response.status);
return response.json();
})
.then(data => {
if (data.links && data.links.length > 0) {
const startPos = textarea.selectionStart;
const endPos = textarea.selectionEnd;
const hasTextBefore = textarea.value.substring(0, startPos).trim().length > 0;
let bbcodeInsert = hasTextBefore ? '\r\n\r\n' : '';
data.links.forEach((link, index) => {
bbcodeInsert += `[img]${link}[/img]`;
if (index < data.links.length - 1) {
bbcodeInsert += '\r\n\r\n\r\n';
}
});
bbcodeInsert += '\r\n\r\n';
const textBefore = textarea.value.substring(0, startPos);
const textAfter = textarea.value.substring(endPos, textarea.value.length);
textarea.value = textBefore + bbcodeInsert + textAfter;
textarea.focus();
textarea.selectionStart = textarea.selectionEnd = startPos + bbcodeInsert.length;
}
})
.catch(error => {
console.error('Ошибка при загрузке:', error.message);
})
.finally(() => {
if (globalFileInput) globalFileInput.value = '';
});
}
function injectUploadButton(colorButton, textarea) {
if (!colorButton || !textarea || colorButton.parentNode.querySelector('.phpbb-fast-upload-trigger')) return;
const newButton = document.createElement('button');
newButton.type = 'button';
newButton.className = 'button button-icon-only phpbb-fast-upload-trigger';
newButton.title = 'Загрузить фото';
newButton.innerHTML = ORIGINAL_ICON;
newButton.style.marginLeft = '4px';
colorButton.parentNode.insertBefore(newButton, colorButton.nextSibling);
newButton.onclick = function(e) {
e.preventDefault();
e.stopPropagation();
const fileInput = getOrCreateFileInput();
fileInput.onchange = null;
fileInput.onchange = function() {
if (!fileInput.files || fileInput.files.length === 0) return;
uploadAndInsertImages(fileInput.files, textarea);
};
fileInput.click();
};
textarea.addEventListener('paste', function(e) {
if (!e.clipboardData || !e.clipboardData.files || e.clipboardData.files.length === 0) {
return;
}
const pastedFiles = [];
for (let i = 0; i < e.clipboardData.files.length; i++) {
const file = e.clipboardData.files[i];
if (file.type.indexOf('image/') !== -1) {
pastedFiles.push(file);
}
}
if (pastedFiles.length > 0) {
e.preventDefault();
uploadAndInsertImages(pastedFiles, textarea);
}
});
}
function autoScanAndInject() {
const colorButtons = document.querySelectorAll('[name="bbpalette"], #bbpalette, .bbcode-color');
if (colorButtons.length > 0) {
colorButtons.forEach(colorBtn => {
const parentForm = colorBtn.closest('form') || colorBtn.closest('.quickreply') || colorBtn.closest('#qr_postform') || document;
const textarea = parentForm.querySelector('textarea');
if (textarea) {
injectUploadButton(colorBtn, textarea);
}
});
}
}
autoScanAndInject();
const observer = new MutationObserver(() => autoScanAndInject());
observer.observe(document.body, { childList: true, subtree: true });
})();
/styles/prosilver/template в самом конце файла overall_footer.html перед закрывающим тегом </html> вставляем одну строку:
Код: Выделить всё
<!-- INCLUDEJS fast_upload.js -->

