Вернуться на предыдущую страницу

Иногда возникают ситуации, когда необходимо скрыть реальный адрес картинок и/или JS файла так, чтобы ссылка на файл была как-бы с Вашего домена, но отдавала файл на удаленном сервере.

В помощь приходит старик PHP со своими CURL'ами...

Что, вообще, значит «проксировать»?

Этот термин в данном случае применяется с тем смыслом, что у Вас, к примеру, есть файл с адресом https://partner-site.org/image.jpg (это сайт Вашего партнера, где расположены изображения, например, рекламные). А site.com - это Ваш сайт и Вы можете по адресу https://site.com/image.jpg показать то же изображение, которое отдает сайт партнера, только уже со своего адреса. К примеру, это можно использовать для обхода блокировщика рекламы.

Вот такой код использовал я для того, чтобы проксировать image файлы. 

У меня адрес проксируемых картинок выглядел так: https://site.com/proxy-{шаблон} - шаблон - это был закодированный код со ссылкой на картинку.
К примеру, адрес картинки был такой: https://partner-site.org/image.jpg, в закодированном виде он был: dnfgpnw4i59y0zd9u94a3ta49ht90h9erg04a3t
в результате ссылка получалась:
https://site.com/proxy-dnfgpnw4i59y0zd9u94a3ta49ht90h9erg04a3t
откуда я затем отсекал \proxy-\ и расшифровывал ссылку на картинку. Но все можно сделать проще. Просто закодировать её с помощью base64encode('https://partner-site.org/image.jpg')

Проксируем изображения:

У меня этот код лежит в файле proxу.php

<?php
/*
 * source: https://gist.github.com/searsia/e141c4aca4ca1f3bd8a2c04877f4b26e
 * */
$route=getenv('REQUEST_URI');//если данная директива у Вас не работает, используйте $_SERVER['REQUEST_URI']
$route=str_replace('/proxy-','',base64decode($route));//Вы можете зашифровать ссылку
$url='https://'.$route;
$mg=stripos($url,'partner-site.org');
if($mg===false){//если в зашифрованной ссылке не содержится сайт партнера (а, к примеру, кто-то пытается использовать данный прокси для своих нужд (НО НЕ ВЫ))
 exit;//... то выйдем из приложения
}

# Check if the client already has the requested item
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) or
 isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
 header('HTTP/1.1 304 Not Modified');
 exit;
}

$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_USERAGENT, 'Searsia/1.0');
curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 4);
curl_setopt($ch, CURLOPT_BUFFERSIZE, 12800);
curl_setopt($ch, CURLOPT_NOPROGRESS, false);
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, function($DownloadSize, $Downloaded, $UploadSize, $Uploaded) { return ($Downloaded > 1024 * 1024) ? 1 : 0; } ); # max 500kb
$out = curl_exec ($ch);
curl_close ($ch);

$file_array = explode("\r\n\r\n", $out, 2);
$header_array = explode("\r\n", $file_array[0]);
foreach($header_array as $header_value) {
 $header_pieces = explode(': ', $header_value);
 if(count($header_pieces) == 2) {
 $headers[$header_pieces[0]] = trim($header_pieces[1]);
 }
}

if (array_key_exists('Location', $headers)) {
 $newurl = urlencode($headers['Location']);
 header("HTTP/1.1 301 Moved Permanently");
 header('Location: ' . $newurl);
} else {
 if(!empty($headers['content-length'])){
 header('content-length: ' . (int)$headers['content-length']);
 }
 if(!empty($headers['content-type'])){
 if (preg_match('#image/webp|image/png|image/.*icon|image/jpe?g|image/gif#', $headers['content-type']) !== 1) {
 header('HTTP/1.1 404 Not Found');
 exit;
 }
 header('content-type: ' . $headers['content-type']);
 }
 echo $file_array[1];
}

В корне Вашего сайта наверняка есть index.php, в котором можно проверить запрашиваемую GET ссылку. И если она содержит /proxy-, то мы подгрузим нужный файлик (proxy.php). Не забывайте, что в данной логике НЕТ index.php в содержании URL! Т.е. Вы либо в htaccess убираете, либо в nginx смотрите здесь как. Либо можно использовать с index.php, но это уже сами придумайте)

$route=getenv('REQUEST_URI');//если данная директива у Вас не работает, используйте $_SERVER['REQUEST_URI']
$detectProxy=substr($route,0,7);
if(!empty($detectProxy) AND $detectProxy=='/proxy-'){
$f='/proxy.php';
if(!is_file($f)){
header('HTTP/1.0 404 Not found');exit;
}
include $f;
exit;
}

Т.е. теперь Вам просто нужно передать ссылку в html коде:

<?php
echo '<img src="/proxy-'.base64encode('https://partnet-site.org/image.jpg').'" alt>';
?>

И браузер запросит её с Вашего домена, а придет она с домена Вашего партнера... Но об этом никто не узнает, кроме Вас)

Проксирование JS:

Для JS у меня немного другая логика, т.к. мне нужно было проксировать всего 5 JS файлов. Поэтому я сделал ссылку вида https://site.com/pjs-1 и, соответственно, отдавал нужный мне файл через прокси — партнерский JS код.

<?php
$arRoute=explode('-',$route);
if($arRoute[0]!==clear('/pjs')){echo 'Err01 PJS';exit;}
$int_=abs((int)$arRoute[1]);
if($int_<1 OR $int_>6){echo 'Err02 PJS';exit;}

switch ($int_){
case 1:
$js='https://jsc.co.uk/m/u/site.org.3.js';
break;
case 2:
$js='https://jsc.co.uk/m/u/site.org.8.js';
break;
case 3:
$js='https://jsc.co.uk/m/u/site.org.7.js';
break;
case 4:
$js='https://jsc.co.uk/m/u/site.org.9.js';
break;
case 5:
$js='https://jsc.co.uk/m/u/site.org.1.js';
break;
}

/*
* source: https://gist.github.com/searsia/e141c4aca4ca1f3bd8a2c04877f4b26e
* */

$url=$js;
# Check if the client already has the requested item
if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) or
isset($_SERVER['HTTP_IF_NONE_MATCH'])) {
header('HTTP/1.1 304 Not Modified');
exit;
}
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HEADER, true);
curl_setopt($ch, CURLOPT_USERAGENT, 'Searsia/1.0');
curl_setopt($ch, CURLOPT_BINARYTRANSFER, true);
curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 4);
curl_setopt($ch, CURLOPT_BUFFERSIZE, 12800);
curl_setopt($ch, CURLOPT_NOPROGRESS, false);
curl_setopt($ch, CURLOPT_PROGRESSFUNCTION, function($DownloadSize, $Downloaded, $UploadSize, $Uploaded) { return ($Downloaded > 1024 * 1024) ? 1 : 0; } ); # max 500kb
$out = curl_exec ($ch);
curl_close ($ch);

$file_array = explode("\r\n\r\n", $out, 2);
$header_array = explode("\r\n", $file_array[0]);
foreach($header_array as $header_value) {
$header_pieces = explode(': ', $header_value);
if(count($header_pieces) == 2) {
$headers[$header_pieces[0]] = trim($header_pieces[1]);
}
}

if (array_key_exists('Location', $headers)) {
$newurl = urlencode($headers['Location']);
header("HTTP/1.1 301 Moved Permanently");
header('Location: ' . $newurl);
} else {
if(!empty($headers['content-length'])){
header('content-length: ' . (int)$headers['content-length']);
}
if(!empty($headers['content-type'])){
if (preg_match('#application/javascript|text/javascript#', $headers['content-type']) !== 1) {
header('HTTP/1.1 404 Not Found');
exit;
}
header('content-type: application/javascript');
}
echo $file_array[1];
}

В index.php:

$detectProxy2=substr($route,0,4);
if(!empty($detectProxy2) AND $detectProxy2=='/pjs'){
$f='/proxy-js.php';
if(!is_file($f)){
header('HTTP/1.0 404 Not found');exit;
}
include $f;
exit;
}

Ссылка на проксированный мною JS выглядела так:

<script src="/pjs-1" async></script>

Важно понимать, что основным отличием, исключая нужную мне логику, является вот эти строчки:

if (preg_match('#application/javascript|text/javascript#', $headers['content-type']) !== 1) {
header('content-type: application/javascript');

где я подставляю нужный content-type для браузера, чтобы он правильно воспринимал файл: картинку, как картинку; js как js. Если Вам необходимо проксировать ккие-то другие форматы, ищите MIME и формат, подставляя вместо application/javascript ...