# PHP cURL 代理接入示例

使用 PHP cURL 扩展、账密环境变量和连接超时完成代理请求。

PHP 服务可以使用 cURL 扩展配置代理主机、端口和认证，凭据不需要拼接到目标 URL 中。

## 前置条件

- PHP 运行环境已启用 cURL 扩展。
- 通过受控环境注入 `PROXY_HOST`、`PROXY_PORT`、`PROXY_USERNAME` 和 `PROXY_PASSWORD`。
- 生产环境关闭包含敏感请求信息的详细调试输出。

## 完整示例

```php
<?php

$handle = curl_init('https://<public-test-host>/ip');
curl_setopt_array($handle, [
    CURLOPT_PROXY => getenv('PROXY_HOST'),
    CURLOPT_PROXYPORT => (int) getenv('PROXY_PORT'),
    CURLOPT_PROXYTYPE => CURLPROXY_HTTP,
    CURLOPT_PROXYUSERPWD => sprintf(
        '%s:%s',
        getenv('PROXY_USERNAME'),
        getenv('PROXY_PASSWORD')
    ),
    CURLOPT_CONNECTTIMEOUT => 10,
    CURLOPT_TIMEOUT => 30,
    CURLOPT_RETURNTRANSFER => true,
]);

$body = curl_exec($handle);
if ($body === false) {
    $message = curl_error($handle);
    curl_close($handle);
    throw new RuntimeException($message);
}

$status = curl_getinfo($handle, CURLINFO_RESPONSE_CODE);
curl_close($handle);
if ($status >= 400) {
    throw new RuntimeException("HTTP {$status}");
}

echo $body;
```

## 预期结果

- cURL 使用 HTTP 代理访问 HTTPS 目标并返回出口信息。
- 连接最长等待 10 秒，整个请求最长等待 30 秒。
- 业务代码同时检查传输错误和 HTTP 状态。

## 错误处理

- 407 优先检查 `CURLOPT_PROXYUSERPWD` 对应的账密是否完整。
- 连接超时先检查代理地址、端口和服务器出口网络。
- TLS 错误不应通过关闭证书校验来掩盖。

## 安全提示

不要启用会记录认证头的公开调试日志。异常上报前移除代理 URL、代理用户名和密码，只保留 cURL 错误码与脱敏上下文。

html pre.shiki code .szBVR, html code.shiki .szBVR{--shiki-default:#D73A49;--shiki-dark:#F97583}html pre.shiki code .sj4cs, html code.shiki .sj4cs{--shiki-default:#005CC5;--shiki-dark:#79B8FF}html pre.shiki code .sVt8B, html code.shiki .sVt8B{--shiki-default:#24292E;--shiki-dark:#E1E4E8}html pre.shiki code .sZZnC, html code.shiki .sZZnC{--shiki-default:#032F62;--shiki-dark:#9ECBFF}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}
