宝塔用户_ogyvui 发表于 2024-7-6 16:39:28

【已完成】php fsockopen() 发送请求的问题

面板、插件版本:免费版8.0.5
系统版本:Debian 12
问题描述:php fsockopen() 发送请求的问题,基本上可以排除代码本身的问题,请求同站点上的地址返回400HTTP/1.1 400 Bad Request
Date: Sat, 06 Jul 2024 08:17:42 GMT
Server: Apache
Content-Length: 292
Connection: close
Content-Type: text/html; charset=iso-8859-1

Your browser sent a request that this server could not understand.Apache Server at ssl.default.com Port 443
相关截图(日志、错误):

宝塔用户_ogyvui 发表于 2024-7-6 16:45:15

<?php

/**
* 异步请求
* @author
* @see
* @version 1.0.1 2023-07-11
*/

namespace Classes\Function;

class AsynRequest
{

    /**
   * 获取URL各参数
   * @param string $url
   * @return array
   */
    private static function getUrlInfo(string $url): array
    {
      $url_arr = parse_url($url);
      $url_info = [
            'hostname' => $url_arr['host'],
            'host' => $url_arr['host'],
            'port' => 80,
            'path' => $url_arr['path'] ?? '/'
      ];
      if ('https' === $url_arr['scheme']) {
            $url_info['hostname'] = 'ssl://' . $url_arr['host'];
            $url_info['port'] = 443;
      }
      return $url_info;
    }

    /**
   * GET请求
   * @param string $url
   * @param array $data = []
   * @param int $timeout = 20
   * @return bool
   */
    public static function get(string $url, array $data = [], int $timeout = 20): bool
    {
      $url_info = self::getUrlInfo($url);
      $data = http_build_query($data);
      $fp = fsockopen($url_info['hostname'], $url_info['port'], $errno, $errstr, $timeout);
      if (!$fp) {
            return false;
      }
      stream_set_blocking($fp, true);
      stream_set_timeout($fp, $timeout);
      $out = 'GET ' . $url_info['path'] . '?' . $data . ' HTTP/1.1' . PHP_EOL;
      $out .= 'Host: ' . $url_info['host'] . PHP_EOL;
      $out .= 'Content-Type: text/xml; charset=utf-8' . PHP_EOL;
      $out .= 'Connection: Close' . PHP_EOL . PHP_EOL;
      fputs($fp, $out);
      while (!feof($fp)) {
            echo fgets($fp, 128);
      }
      usleep(10000);
      fclose($fp);
      return true;
    }

    /**
   * POST请求
   * @param string $url
   * @param array $data = []
   * @param int $timeout = 20
   * @param string $content_type = 'application/json'
   * @return bool
   */
    public static function post(string $url, array $data = [], int $timeout = 20, string $content_type = 'application/json'): bool
    {
      $url_info = self::getUrlInfo($url);
      $data = json_encode($data);
      $fp = fsockopen($url_info['hostname'], $url_info['port'], $errno, $errstr, $timeout);
      if (!$fp) {
            return false;
      }
      stream_set_blocking($fp, true);
      stream_set_timeout($fp, $timeout);
      $out = 'POST ' . $url_info['path'] . ' HTTP/1.1' . PHP_EOL;
      $out .= 'Host: ' . $url_info['host'] . PHP_EOL;
      $out .= 'Content-Type: ' . $content_type . '; charset=utf-8' . PHP_EOL;
      $out .= 'Content-Length: ' . strlen($data) . PHP_EOL;
      $out .= 'Connection: Close' . PHP_EOL . PHP_EOL;
      $out .= $data . PHP_EOL;
      fwrite($fp, $out);
      while (!feof($fp)) {
            echo fgets($fp, 128);
      }
      usleep(10000);
      fclose($fp);
      return true;
    }

}

运维技术阿闯 发表于 2024-7-6 17:20:13

宝塔用户_ogyvui 发表于 2024-7-6 16:45


您好,您这百年尝试使用以下方式来执行一下
public static function get(string $url, array $data = [], int $timeout = 20): bool
{
    $url_info = self::getUrlInfo($url);
    $data = http_build_query($data);
    $fp = fsockopen($url_info['hostname'], $url_info['port'], $errno, $errstr, $timeout);
    if (!$fp) {
      return false;
    }
    stream_set_blocking($fp, true);
    stream_set_timeout($fp, $timeout);
    $out = 'GET ' . $url_info['path'] . '?' . $data . ' HTTP/1.1' . PHP_EOL;
    $out .= 'Host: ' . $url_info['host'] . PHP_EOL;
    $out .= 'Content-Type: application/x-www-form-urlencoded; charset=utf-8' . PHP_EOL; // 修改Content-Type
    $out .= 'Connection: Close' . PHP_EOL . PHP_EOL;
    fputs($fp, $out);
    while (!feof($fp)) {
      echo fgets($fp, 128);
    }
    usleep(10000);
    fclose($fp);
    return true;
}

宝塔用户_ogyvui 发表于 2024-7-6 17:24:12

运维技术阿闯 发表于 2024-7-6 17:20
您好,您这百年尝试使用以下方式来执行一下

你好,也是一样的,这个Content-Type尝试过不同的内容,任然是一样的,返回 400
public static function get(string $url, array $data = [], int $timeout = 20): bool
    {
      $url_info = self::getUrlInfo($url);
      $data = http_build_query($data);
      $fp = fsockopen($url_info['hostname'], $url_info['port'], $errno, $errstr, $timeout);
      if (!$fp) {
            return false;
      }
      stream_set_blocking($fp, true);
      stream_set_timeout($fp, $timeout);
      $out = 'GET ' . $url_info['path'] . '?' . $data . ' HTTP/1.1' . PHP_EOL;
      $out .= 'Host: ' . $url_info['host'] . PHP_EOL;
      $out .= 'Content-Type: application/x-www-form-urlencoded; charset=utf-8' . PHP_EOL;
      $out .= 'Connection: Close' . PHP_EOL . PHP_EOL;
      fputs($fp, $out);
      while (!feof($fp)) {
            echo fgets($fp, 128);
      }
      usleep(10000);
      fclose($fp);
      return true;
    }

运维技术阿闯 发表于 2024-7-6 18:02:47

宝塔用户_ogyvui 发表于 2024-7-6 17:24
你好,也是一样的,这个Content-Type尝试过不同的内容,任然是一样的,返回 400
...

您好,您这边在这个贴子里边的尝试一下
https://blog.csdn.net/zjsfdx/article/details/89376176

宝塔用户_ogyvui 发表于 2024-7-6 18:22:39

运维技术阿闯 发表于 2024-7-6 18:02
您好,您这边在这个贴子里边的尝试一下
https://blog.csdn.net/zjsfdx/article/details/89376176 ...

谢谢,找到根本原因了,已解决。
PHP_EOL 替换成 \r\n 就可以了。

运维技术阿闯 发表于 2024-7-6 18:32:15

宝塔用户_ogyvui 发表于 2024-7-6 18:22
谢谢,找到根本原因了,已解决。
PHP_EOL 替换成 \r\n 就可以了。

好的,问题解决了就好,后续有问题可以在开新帖呢,这边就闭贴了,祝您生活愉快
页: [1]
查看完整版本: 【已完成】php fsockopen() 发送请求的问题