Иногда возникают ситуации, когда необходимо скрыть реальный адрес картинок и/или 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
...