Прокси для изображений: решение проблемы CORS через .htaccess и PHP

    При разработке расширения для Chrome на JavaScript часто возникает ошибка No 'Access-Control-Allow-Origin' при запросе изображений с внешнего домена. Один из надёжных способов - создать собственный прокси-сервер, который загружает картинки и отдаёт их с нужным заголовком. В этой статье мы разберём, как организовать такую систему с помощью .htaccess и PHP, включая проверку существования папок и файлов.

    Архитектура прокси-решения

    Основная идея: расширение обращается к вашему домену (https://img.site.ru/images/user/avatar.gif), а сервер проверяет, существует ли файл. Если нет - PHP-скрипт создаёт папки, загружает изображение с исходного домена и возвращает его с заголовком Access-Control-Allow-Origin. Это снижает нагрузку на внешний ресурс и решает проблему CORS.

    Настройка .htaccess для маршрутизации запросов

    Чтобы все запросы к папке /images/ обрабатывались через PHP, добавьте в корневой .htaccess следующие правила:

    RewriteEngine On
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule ^images/(.*)$ index.php?request=$1 [L,QSA]

    Этот код перенаправляет все несуществующие файлы и папки в index.php с параметром request. Если файл уже существует, он отдаётся напрямую - без нагрузки на PHP.

    PHP-скрипт для обработки запросов

    В index.php реализуем логику проверки и загрузки:

    <?php
    header('Access-Control-Allow-Origin: *');
    $request = $_GET['request'] ?? '';
    if (!$request || !is_string($request) || strpos($request, '..') !== false) {
        header('Location: https://img.site.ru');
        exit;
    }
    $fullPath = __DIR__ . '/' . $request;
    if (file_exists($fullPath)) {
        $mime = mime_content_type($fullPath);
        header('Content-Type: ' . $mime);
        readfile($fullPath);
        exit;
    }
    $dir = dirname($fullPath);
    if (!is_dir($dir)) {
        mkdir($dir, 0755, true);
    }
    $remoteUrl = 'https://source-domain.com/' . $request;
    $imageData = file_get_contents($remoteUrl);
    if ($imageData !== false) {
        file_put_contents($fullPath, $imageData);
        header('Content-Type: image/png');
        echo $imageData;
    } else {
        http_response_code(500);
        echo 'Ошибка загрузки изображения';
    }
    ?>

    Скрипт проверяет наличие файла, создаёт папки при необходимости, загружает изображение с удалённого сервера и сохраняет его локально. Также добавлена базовая защита от path traversal.

    Обеспечение безопасности поддомена

    Чтобы предотвратить злоупотребления, следуйте этим рекомендациям:

    • Ограничьте типы файлов: разрешите только изображения (png, jpg, gif, webp) через проверку расширения.
    • Защита от path traversal: запретите использование .. в пути.
    • Ограничьте размер файла: используйте filesize() или лимиты на стороне PHP.
    • Кэширование: добавьте заголовки Cache-Control для уменьшения нагрузки.

    Альтернативный подход: прямой запрос через ?request=

    Можно отказаться от .htaccess и просто делать запросы к https://img.site.ru/?request=images/avatar.png. Этот вариант проще, но менее красив с точки зрения URL. Выбор зависит от ваших требований к эстетике ссылок.

    Обработка ошибок и редиректы

    При неверном запросе (например, отсутствует параметр request или он содержит недопустимые символы) лучше всего перенаправлять пользователя на главную страницу домена или возвращать 404. В примере выше используется редирект на https://img.site.ru.

    Часто задаваемые вопросы