Я хочу получить HTTP-запрос GET, отправленный с PHP. Пример:
http://tracker.example.com?product_number=5230&price=123.52
Идея состоит в том, чтобы сделать веб-аналитику на стороне сервера: вместо отправки информации отслеживания с JavaScript на сервер сервер отправляет информацию отслеживания непосредственно на другой сервер.
Требования:
Запрос должен занимать как можно меньше времени, чтобы не заметно замедлить обработку страницы PHP.
Ответ от tracker.example.com
не нужно проверять. В качестве примера можно привести некоторые возможные ответы от tracker.example.com
:
200: Это нормально, но не нужно это проверять.
404: Не повезло, но – опять – нет необходимости проверять это.
301: Хотя перенаправление было бы уместным, это задерживало бы обработку страницы PHP, поэтому не делайте этого.
Короче: все ответы могут быть отброшены.
Идеи для решений:
В недавно удаленном ответе кто-то предложил вызвать кривую командной строки из PHP в процессе оболочки. Это кажется хорошей идеей, только я не знаю, является ли многократная обработка процессов оболочки под большой нагрузкой.
Я нашел php-ga , пакет для создания серверной Google Analytics с PHP. На странице проекта упоминается: «Можно настроить на […] использование неблокирующих запросов». До сих пор я не нашел времени для изучения того, какой метод php-ga использует внутри, но этот метод может быть таким!
Вкратце: что является лучшим решением для создания общего отслеживания / аналитики на стороне сервера с PHP.
К сожалению, PHP по определению блокирует . Хотя это справедливо для большинства функций и операций, которые вы обычно обрабатываете, текущий сценарий отличается.
Процесс, который мне нравится называть HTTP-Ping , требует, чтобы вы касались только определенного URI, заставляя конкретный сервер загружаться, это внутренняя логика. Некоторые функции позволяют достичь чего-то очень похожего на этот HTTP-пинг , не дожидаясь ответа.
Обратите внимание, что процесс пинга URL-адреса является двухэтапным процессом:
Хотя запрос должен быть довольно быстрым после того, как DNS будет разрешен и будет установлено соединение, не так много способов сделать DNS-разрешение быстрее.
Некоторые способы выполнения http-ping:
STREAM_CLIENT_ASYNC_CONNECT
Хотя оба cURL
и fsockopen
блокируются при разрешении DNS. Я заметил, что fsockopen значительно быстрее, даже в самых худших сценариях.
stream_socket_client
с другой стороны, должен исправить проблему разрешения DNS и должен быть оптимальным решением в этом сценарии, но мне не удалось заставить его работать.
Одним из окончательных решений является запуск другого потока / процесса, который сделает это за вас. Выполнение системного вызова для этого должно работать, но также и для того, чтобы развернуть текущий процесс. К сожалению, обе версии не очень безопасны в приложениях, где вы не можете контролировать среду, на которой работает PHP.
Системные вызовы чаще всего блокируются, а по умолчанию pcntl не включен.
Я бы назвал tracker.example.com следующим образом:
get_headers('http://tracker.example.com?product_number=5230&price=123.52');
и в сценарии трекера:
ob_end_clean(); ignore_user_abort(true); ob_start(); header("Connection: close"); header("Content-Length: " . ob_get_length()); ob_end_flush(); flush(); // from here the response has been sent. you can now wait as long as you want and do some tracking stuff sleep(5); //wait 5 seconds do_some_stuff(); exit;
Я реализовал функцию быстрого запроса GET для URL-адреса, не дожидаясь ответа:
function fast_request($url) { $parts=parse_url($url); $fp = fsockopen($parts['host'],isset($parts['port'])?$parts['port']:80,$errno, $errstr, 30); $out = "GET ".$parts['path']." HTTP/1.1\r\n"; $out.= "Host: ".$parts['host']."\r\n"; $out.= "Content-Length: 0"."\r\n"; $out.= "Connection: Close\r\n\r\n"; fwrite($fp, $out); fclose($fp); }
Вы можете использовать shell_exec и curl командной строки.
Например, см. Этот вопрос
Пришел сюда, исследуя аналогичную проблему. Если у вас есть соединение с базой данных, еще одна возможность – быстро направить данные запроса в таблицу, а затем выполнить отдельный процесс на основе cron, который периодически сканирует эту таблицу для обработки новых записей и делает запрос отслеживания, освобождая от вашего веб-приложения от необходимости самому делать запрос HTTP.
<?php // Create a stream $opts = array( 'http'=>array( 'method'=>"GET", 'header'=>"Accept-language: en" ) ); $context = stream_context_create($opts); // Open the file using the HTTP headers set above $file = file_get_contents('http://tracker.example.com?product_number=5230&price=123.52', false, $context); ?>
Вы можете сделать это, используя CURL
напрямую.
Я выполнил его с использованием очень короткого таймаута ( CURLOPT_TIMEOUT_MS
) и / или с помощью curl_multi_exec
.
Будьте внимательны: в конце концов я выхожу из этого метода, потому что не каждый запрос был правильно сделан. Это могло быть вызвано моим собственным сервером, хотя я не смог исключить возможность зависания завитка.