重定向以重命名远程图像以绕过 adblock

Redirect to rename remote images so as to get around adblock

我正在与一个合作伙伴合作,该合作伙伴向我提供来自 API 的他们的产品图片。图片以 URL 的形式发送,他们希望我只在 img 标签中使用这些 URL,而不是下载图片并在本地提供它们。

问题是 1/4 的用户使用广告拦截器,他们的图片有像 https://example.com/ad-image/ads/1234/500.jpg 这样的 URL,广告拦截器将其读作广告(从技术上讲,它们当然是广告)。是否可以设置重定向以便像 <img src="/image-redirects/500.jpg"> 这样的 img 标签向他们显示来自 https://example.com/ad-image/ads/1234/500.jpg 的图像?那可行吗?会不会因为它们是远程托管的图像而无论如何都不会出现?

Would it be possible to set up a redirect so an img tag like <img src="/image-redirects/500.jpg"> would show them the image from https://example.com/ad-image/ads/1234/500.jpg?

是的,你可以,但不能使用外部“重定向”,因为它只会在重定向响应中将目标 URL 呈现给浏览器(并被阻止 - 如果浏览器仅基于以下内容进行阻止URl).

中的关键字

反向代理

您需要将您的服务器配置为反向代理(使用 mod_proxy 和相关模块,最好在服务器配置中使用 ProxyPass / ProxyPassReverse),然后您可以这样做.htaccess(在 WordPress 前端控制器之前)使用 mod_rewrite 通过 mod_proxy:

路由请求
RewriteRule ^image-redirects/(\d+\.jpg)$ https://example.com/ad-image/ads/1234/ [P]

(假设 500 是仅由数字组成的动态文件名 - 如您的示例所示)。

PHP 获取图像的脚本

或者,您在内部将此类请求重写为 PHP 脚本,该脚本从远程服务器获取图像并将其发回响应。

例如,在 .htaccess 中,使用 mod_rewrite(同样,在 WP 前端控制器之前):

RewriteRule ^image-redirects/(\d+\.jpg)$ image-fetch-script.php?file= [L]

image-fetch-script.php 中,您可以检查 file URL 参数并从远程服务器获取预期图像,然后在响应中将其发送回客户端。您还可以将图像缓存在服务器上一段时间。然而,他们希望您直接从他们的服务器获取图像的事实可能是因为他们正在记录 印象,因此本地缓存会影响这一点。

示例 image-fetch-script.php 可能类似于:

<?php
/**
 * Fetch remote image and send to client
 */

// Remote URL from which to fetch images
$remoteBaseUrl = 'https://example.com/ad-image/ads/1234/';

// Permitted file extensions / mime-types
// NB: If using CURL, can get the mime-type from the HTTP response instead
$mimeTypes = [
    'gif' => 'image/gif',
    'jpg' => 'image/jpeg',
    'png' => 'image/png',
    'webp' => 'image/webp',
];

// Get the reqd file the "file" URL parameter in the rewritten URL
$file = $_GET['file'] ?? null;
$remoteUrl = null;

// Validate filename format
// Or even check against a known list of files?
$filenameRegex = '/^[\w-]+\.('.implode('|',array_keys($mimeTypes)).')$/';
if (preg_match($filenameRegex, $file, $matches)) {
    header('Content-Type: '.$mimeTypes[$matches[1]]);
    $remoteUrl = $remoteBaseUrl.$file;

    // OPTIONAL: Check cache here...
    // readfile() and exit if current.

    // Using readfile()
    // - simple, but does not provide any error handling on the HTTP response
    //   eg. if the remote file does not exist etc.
    //$bytes = readfile($remoteUrl);
    //if ($bytes === false) {
    //    General 500 Internal Server Error
    //    http_response_code(500);  
    //} else {
    //    // No error - assume success!
    //    // But there could have been an HTTP response "error" that is lost
    //}
    //exit;

    // Using CURL
    $ch = curl_init($remoteUrl);
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    $content = curl_exec($ch);
    $curlError = curl_errno($ch);
    if ($curlError) $curlError .= ': '.curl_error($ch);
    $httpStatus = curl_getinfo($ch,CURLINFO_RESPONSE_CODE);
    curl_close($ch);

    if ($curlError) {
        // Only set header when debugging, otherwise could expose the target URL
        //header('X-CURL-ERROR: '.$curlError);

        // General 500 Internal Server Error
        http_response_code(500);    
    }
    // CURL request is OK, but could still be an HTTP failure...
    else {
        // OK - serve image
        if ($httpStatus === 200) {
            // OPTIONAL: Save to cache...
            echo $content;
        }
        // Pass through HTTP status from CURL request... 404, 403, etc...
        else {
             http_response_code($httpStatus);
        }
    }
    exit;
}

// Default failure... "Bad Request"
http_response_code(400);