48

我想从 PHP 发送一个 HTTP GET 请求。例子:

http://tracker.example.com?product_number=5230&price=123.52

这个想法是做服务器端的网络分析:服务器不是将跟踪信息从 JavaScript 发送到服务器,而是将跟踪信息直接发送到另一台服务器。

要求:

  • 请求应该花费尽可能少的时间,以便不会明显延迟 PHP 页面的处理。

  • tracker.example.com不需要检查来自的响应。例如,一些可能的回应来自 tracker.example.com

    • 200:那很好 但不需要检查

    • 404:运气不好,但是 - 再次 - 不需要检查。

    • 301:虽然重定向是合适的,但它会延迟 PHP 页面的处理,所以不要这样做。

    简而言之:可以丢弃所有响应。

解决方案的想法:

  • 在一个现已删除的答案中,有人建议 在 shell 进程中从 PHP调用命令行curl 。这似乎是个好主意,只是我不知道在重负载下分叉很多 shell 进程是否是明智之举。

  • 我找到了php-ga,一个用于从 PHP 执行服务器端 Google Analytics 的包。在项目页面上,提到:“可以配置为 [...] 使用非阻塞请求。” 到目前为止我还没有时间研究php-ga内部使用什么方法,但是这个方法可能就是它!

简而言之:从 PHP 进行通用服务器端跟踪/分析的最佳解决方案是什么。

4

10 回答 10

35

不幸的是,PHP 根据定义是阻塞的。虽然这适用于您通常要处理的大多数功能和操作,但当前情况有所不同。

我喜欢称之为HTTP-Ping的过程要求您只触摸一个特定的 URI,强制特定的服务器引导它的内部逻辑。某些功能允许您通过不等待响应来实现与此HTTP-ping非常相似的功能。

请注意,ping url 的过程是一个两步过程:

  1. 解析 DNS
  2. 提出请求

虽然在解析 DNS 并建立连接后发出请求应该相当快,但没有很多方法可以使 DNS 解析得更快。

进行 http-ping 的一些方法是:

  1. cURL,通过将 CONNECTION_TIMEOUT 设置为低值
  2. fsockopen写入后立即关闭
  3. stream_socket_client(与 fsockopen 相同)并添加STREAM_CLIENT_ASYNC_CONNECT

在解析 DNS 时,两者都阻塞cURLfsockopen我注意到fsockopen明显更快,即使在最坏的情况下也是如此。

stream_socket_client另一方面,应该解决有关 DNS 解析的问题,并且应该是这种情况下的最佳解决方案,但我还没有设法让它工作。

一个最终的解决方案是启动另一个为您执行此操作的线程/进程。对此进行系统调用应该可以工作,但分叉当前进程也应该这样做。不幸的是,在您无法控制 PHP 运行环境的应用程序中,两者都不是真正安全的。

系统调用经常被阻止,默认情况下不启用 pcntl。

于 2013-02-03T02:03:10.247 回答
18

我会这样调用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;
于 2014-02-07T16:19:40.050 回答
12

我实现了快速 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);
}
于 2016-08-02T19:42:06.380 回答
4

我们正在使用fsockopenfwrite组合,然后有一天它停止工作。或者它是一种间歇性的。经过一些研究和测试,如果你启用了 fopen 包装器,我最终使用file_get_contentsstream_context_create函数,超时设置为 100 秒。timeout 参数可以接收浮动值(https://www.php.net/manual/en/context.http.php)。我将它包装在一个 try...catch 块中,这样它就会默默地失败。它非常适合我们的目的。如果需要,您可以在 catch 中记录内容。如果您不希望函数阻塞运行时,超时是关键。

function fetchWithoutResponseURL( $url )
{

    $context = stream_context_create([
        "http" => [
            "method"=>"GET",
            "timeout" => .01
            ]
        ]
    );

    try {
        file_get_contents($url, 0, $context);
    }catch( Exception $e ){
        // Fail silently
    }
}
于 2020-07-15T16:27:36.940 回答
3

您可以使用shell_exec, 和命令行 curl。

例如,请参阅此问题

于 2013-01-16T13:54:23.670 回答
2

在研究类似问题时来到这里。如果您有一个方便的数据库连接,另一种可能性是将请求详细信息快速填充到一个表中,然后有一个单独的基于 cron 的进程定期扫描该表以查找要处理的新记录,并发出跟踪请求,从而释放您的 Web 应用程序不必自己发出 HTTP 请求。

于 2013-07-04T00:25:11.137 回答
1

对于那些使用 wordrpess 作为后端的人来说——它很简单:

wp_remote_get( $url, array(blocking=>false) );

于 2020-03-03T07:08:50.283 回答
-1

您实际上可以CURL直接使用。

我都使用非常短的超时 ( CURLOPT_TIMEOUT_MS) 和/或使用curl_multi_exec.

请注意:最终我退出了此方法,因为并非每个请求都正确发出。这可能是由我自己的服务器引起的,尽管我无法排除 curl 失败的选项。

于 2013-01-16T15:34:09.037 回答
-1
<?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);
?>
于 2015-09-19T18:36:11.820 回答
-1

我需要做类似的事情,只需 ping 一个 url 并丢弃所有响应。我使用了 proc_open 命令,它可以让您使用 proc_close 立即结束进程。我假设你的服务器上安装了 lynx:

<?php    
function ping($url) {
      $proc = proc_open("lynx $url",[],$pipes);
      proc_close($proc);
    }
?>
于 2018-04-08T05:11:36.340 回答