logFile = __DIR__ . '/proxy.log'; } private function logMessage($message) { $date = date('Y-m-d H:i:s'); file_put_contents($this->logFile, "[$date] $message\n", FILE_APPEND); } // private function buildTargetUrl() // { // $path = isset($_GET['path']) ? $_GET['path'] : ''; // unset($_GET['path']); // $query = http_build_query($_GET); // // //$apiUrl = "https://api.joywork.ru/" . ltrim($path, '/'); // // $baseUrl = 'https://10.91.76.101'; // // $apiUrl = rtrim($baseUrl, '/') . '/' . ltrim($path, '/'); // // if ($query) { // $apiUrl .= '?' . $query; // } // return $apiUrl; // } private function buildTargetUrl() { $path = isset($_GET['path']) ? $_GET['path'] : ''; unset($_GET['path']); $pathParts = explode('?', $path, 2); $cleanPath = ltrim($pathParts[0], '/'); $queryParams = $_GET; if (isset($pathParts[1]) && $pathParts[1]) { parse_str($pathParts[1], $pathQuery); $queryParams = array_merge($queryParams, $pathQuery); } $query = http_build_query($queryParams); $baseUrl = 'https://10.91.76.101'; $apiUrl = rtrim($baseUrl, '/') . '/' . $cleanPath; if ($query) { $apiUrl .= '?' . $query; } return $apiUrl; } private function buildHeaders() { $headers = array( 'Accept: application/json', 'Host: api.joywork.ru', ); // Preserve original Content-Type if present $originalContentType = isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : ''; if ($originalContentType) { $headers[] = 'Content-Type: ' . $originalContentType; $this->logMessage("Incoming Content-Type: '$originalContentType'"); } else { $this->logMessage('WARNING: Incoming Content-Type not detected'); } // Pass session cookie if exists if (!empty($_COOKIE['PHPSESSID'])) { $headers[] = 'Cookie: PHPSESSID=' . $_COOKIE['PHPSESSID']; } // Pass custom header from Vue if present if (!empty($_SERVER['HTTP_X_SESSION_ID'])) { $headers[] = 'X-Session-ID: ' . $_SERVER['HTTP_X_SESSION_ID']; } return $headers; } private function forwardRequest($targetUrl, $headers, $method, $body) { $ch = curl_init(); curl_setopt_array($ch, array( CURLOPT_URL => $targetUrl, CURLOPT_RETURNTRANSFER => true, CURLOPT_CUSTOMREQUEST => $method, CURLOPT_POSTFIELDS => $body, CURLOPT_HTTPHEADER => $headers, CURLOPT_HEADER => false, )); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false); curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false); curl_setopt($ch, CURLOPT_VERBOSE, true); $verbose = fopen('php://temp', 'w+'); curl_setopt($ch, CURLOPT_STDERR, $verbose); $response = curl_exec($ch); $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $curlError = curl_error($ch); if ($curlError) { rewind($verbose); $verboseLog = stream_get_contents($verbose); $this->logMessage('cURL VERBOSE: ' . $verboseLog); $this->logMessage('cURL Error: ' . $curlError); } else { $this->logMessage('cURL Response (first 200 chars): ' . substr($response, 0, 200)); $this->logMessage('HTTP Code: ' . $httpCode); } curl_close($ch); http_response_code($httpCode); echo $response; } private function buildMultipartBody() { $boundary = '----FormBoundary' . uniqid(); $body = ''; foreach ($_POST as $key => $value) { $body .= "--{$boundary}\r\n"; $body .= "Content-Disposition: form-data; name=\"{$key}\"\r\n\r\n"; $body .= "{$value}\r\n"; } foreach ($_FILES as $key => $file) { if ($file['error'] === UPLOAD_ERR_OK) { $body .= "--{$boundary}\r\n"; $body .= "Content-Disposition: form-data; name=\"{$key}\"; filename=\"{$file['name']}\"\r\n"; $body .= "Content-Type: {$file['type']}\r\n\r\n"; $body .= file_get_contents($file['tmp_name']) . "\r\n"; } } $body .= "--{$boundary}--\r\n"; return ['body' => $body, 'boundary' => $boundary]; } public function handle() { $this->logMessage('=== PROXY REQUEST START ==='); $this->logMessage('Method: ' . $_SERVER['REQUEST_METHOD']); $this->logMessage('GET params: ' . print_r($_GET, true)); $this->logMessage('HTTP_X_SESSION_ID: ' . (isset($_SERVER['HTTP_X_SESSION_ID']) ? $_SERVER['HTTP_X_SESSION_ID'] : 'NOT SET')); $this->logMessage('HTTP_COOKIE: ' . (isset($_SERVER['HTTP_COOKIE']) ? $_SERVER['HTTP_COOKIE'] : 'NOT SET')); $this->logMessage('Raw input: ' . file_get_contents('php://input')); $this->logMessage('FILES: ' . print_r($_FILES, true)); $this->logMessage('POST: ' . print_r($_POST, true)); // CORS headers header('Access-Control-Allow-Origin: *'); header('Access-Control-Allow-Credentials: true'); header('Access-Control-Allow-Methods: GET, POST, PUT, DELETE, OPTIONS'); header('Access-Control-Allow-Headers: Accept, Content-Type, X-Requested-With, Authorization'); if ($_SERVER['REQUEST_METHOD'] === 'OPTIONS') { http_response_code(204); exit; } $targetUrl = $this->buildTargetUrl(); $headers = $this->buildHeaders(); $method = $_SERVER['REQUEST_METHOD']; $originalContentType = isset($_SERVER['CONTENT_TYPE']) ? $_SERVER['CONTENT_TYPE'] : ''; if (strpos($originalContentType, 'multipart/form-data') !== false && !empty($_FILES)) { $multipart = $this->buildMultipartBody(); $body = $multipart['body']; $headers = array_filter($headers, function($h) { return strpos($h, 'Content-Type:') === false; }); $headers[] = 'Content-Type: multipart/form-data; boundary=' . $multipart['boundary']; $this->logMessage('Rebuilt multipart body from $_POST/$_FILES'); } else { $body = file_get_contents('php://input'); } $this->logMessage('Forwarding request to ' . $targetUrl); $this->forwardRequest($targetUrl, $headers, $method, $body); } }