Прокси

Бывают случаи, когда напрямую узел сети не доступен, так как до него нет маршрута (ох уж эти админы). Используем прокси - nginx.

Конфиг nginx

/etc/nginx/sites-available/proxy.conf
server {
  server_name _;
  listen 8090; # порт прокси
  error_log /var/log/nginx/proxy-error.log error;
  access_log /var/log/nginx/proxy-access.log combined;
  location / {
     resolver 8.8.8.8; # DNS resolver, можно указать свой, из корп сети
     proxy_pass http://$http_host$uri$is_args$args;
  }
}

Проверяем прокси

Перезагружаем конфиг nginx и узнаем IP адрес нашего нового прокси:

sudo service nginx reload
ip addr

Например, прокси на 10.0.1.18:8090, а нужен узел 10.2.0.66. Проверяем, работает ли прокси из баша на удаленной машине (пример с базовой авторизацией):

export http_proxy=http://10.0.1.18:8090/
curl --user user:password -i http://10.2.0.66/some-uri

Должны отдаться заголовки и ответ. Если все норм, идем дальше - используем прокси в PHP.

Использование прокси на PHP

Рабочий пример с комментариями:

file_get_contents-proxy.php
public function getDebt($partnerGuid) {
  $uri = sprintf($this->config->uri, $partnerGuid);
 
  // получать тело, даже если вернули не 200 OK
  $httpOptions = array('ignore_errors' => true);
 
  // если есть авторизация, используем ее
  if(isset($this->config->auth->type)) switch($this->config->auth->type) {
    case "Basic":
      $httpOptions['header'] = "Authorization: Basic " . base64_encode("{$this->config->auth->login}:{$this->config->auth->password}");
      break;
  }
 
  // тут стоит указать свой настроенный прокси, например tcp://10.0.1.18:8090/
  if(isset($this->config->proxy)) {
    $httpOptions['proxy'] = $this->config->proxy->uri;
  }
 
  $options = array('http' => $httpOptions);
  $context = stream_context_create($options);
 
  // собственно, получаем данные
  $data = file_get_contents($uri, false, $context);
 
  // смотрим заголовки ответа
  $statusHeaders = preg_grep('~^HTTP\/.*~', $http_response_header);
  if(!is_array($statusHeaders) || count($statusHeaders) == 0) {
    throw new Exception("No headers in response", 1);
  }
 
  $statusHeader = reset($statusHeaders);
  if(!preg_match('~^HTTP\/.*?\s(.*)$~', $statusHeader, $m)) {
    throw new Exception("Wrong headers in response", 1);
  }
 
  switch($m[1]) {
    // ошибок не было
    case '200 OK':
      $data = json_decode($data, true);
      // вернули не JSON
      if(json_last_error() != JSON_ERROR_NONE) throw new Exception("Wrong JSON in response", 1);
      return $data;
    // есть ошибки, разруливаем
    case '400 Bad request':
    default:
      throw new Exception("Error response code: " . $m[1] . PHP_EOL . $data, 1);
  }
}
Печать/экспорт