我正在尝试使用以下PHP代码连接到Tor隐藏服务:
$url = 'http://jhiwjjlqpyawmpjx.onion/'
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_PROXY, "http://127.0.0.1:9050/");
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
$output = curl_exec($ch);
$curl_error = curl_error($ch);
curl_close($ch);
print_r($output);
print_r($curl_error);
当我运行它时,我收到以下错误:
无法解析主机名
但是,当我从Ubuntu的命令行运行以下命令时:
curl -v --socks5-hostname localhost:9050 http://jhiwjjlqpyawmpjx.onion
我得到了预期的回复
PHP cURL文件说明了这一点:
--socks5-hostname
Use the specified SOCKS5 proxy (and let the proxy resolve the host name).
我相信它在命令行中运行的原因是因为Tor(代理)正在解析它识别的.onion主机名。在运行上面的PHP代码时,我的猜测是cURL或PHP正在尝试解析.onion主机名并且无法识别它。我已经搜索了一种告诉cURL / PHP让代理解析主机名的方法,但我找不到办法。
有一个非常类似的Stack Overflow问题, cURL request using socks5 proxy fails when using PHP, but it works through the command line 。
答案 0 :(得分:95)
看起来PHP中没有定义CURLPROXY_SOCKS5_HOSTNAME
,但是你可以明确地使用它的值,它等于7:
curl_setopt($ch, CURLOPT_PROXYTYPE, 7);
答案 1 :(得分:19)
我使用Privoxy和cURL来刮擦Tor页面:
<?php
$ch = curl_init('http://jhiwjjlqpyawmpjx.onion'); // Tormail URL
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
curl_setopt($ch, CURLOPT_PROXY, "localhost:8118"); // Default privoxy port
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_HTTP);
curl_exec($ch);
curl_close($ch);
?>
安装Privoxy后,您需要将此行添加到配置文件(/etc/privoxy/config
)。注意空格和'。'一条线的终点。
forward-socks4a / localhost:9050 .
然后重启Privoxy。
/etc/init.d/privoxy restart
答案 2 :(得分:7)
尝试添加:
curl_setopt($ch, CURLOPT_HEADER, 1);
curl_setopt($ch, CURLOPT_HTTPPROXYTUNNEL, 1);
答案 3 :(得分:2)
TL; DR:如果您使用的是现代PHP,则将CURLOPT_PROXYTYPE
设置为使用CURLPROXY_SOCKS5_HOSTNAME
,否则设置为7
,并且/或者更正CURLOPT_PROXY
的值。
根据正确的推论,您无法通过普通的DNS系统解析.onion
个域,因为这是a reserved top-level domain specifically for use by Tor,而且这种域在设计上没有IP地址可映射。
使用CURLPROXY_SOCKS5
将指示cURL命令将其流量发送到代理,但是不对于域名解析也将执行相同的操作。在 尝试建立与Onion站点的实际连接之前发出的DNS请求仍将发送到系统的常规DNS解析器。这些DNS请求肯定会失败,因为系统的普通DNS解析器将不知道如何处理.onion
地址,除非它也专门将此类查询转发给Tor。
您必须使用CURLPROXY_SOCKS5_HOSTNAME
而不是CURLPROXY_SOCKS5
。另外,您也可以使用CURLPROXY_SOCKS4A
,但是SOCKS5是更可取的。这些代理类型中的任何一种都通知cURL通过代理执行其DNS查找和实际数据传输。要成功解析任何.onion
域,这是必需的。
原始问题中的代码中还有两个其他错误,以前的评论者尚未纠正。这些是:
这是完整的正确代码,带有注释以指示更改。
<?php
$url = 'http://jhiwjjlqpyawmpjx.onion/'; // Note the addition of a semicolon.
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_PROXY, "127.0.0.1:9050"); // Note the address here is just `IP:port`, not an HTTP URL.
curl_setopt($ch, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5_HOSTNAME); // Note use of `CURLPROXY_SOCKS5_HOSTNAME`.
$output = curl_exec($ch);
$curl_error = curl_error($ch);
curl_close($ch);
print_r($output);
print_r($curl_error);
您还可以通过更改CURLOPT_PROXYTYPE
的值以包含CURLOPT_PROXY
前缀来完全省略设置socks5h://
:
// Note no trailing slash, as this is a SOCKS address, not an HTTP URL.
curl_setopt(CURLOPT_PROXY, 'socks5h://127.0.0.1:9050');
答案 4 :(得分:0)
这里有一个简单的功能可以帮助您。 为了节省时间,首先您需要确保检查代理是否有效,而不是使用 fsocketopen() 进行简单检查
try {
$fp = fsockopen($ip, $port, $errno, $errstr, 10);
fclose($fp);
return true;
} catch (\Throwable $th) {
return false;
}
如果 socket 返回 true 则使用 requestUrl 函数
private function requestUrl($url, $proxy)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_PROXY, $proxy);
curl_setopt($curl, CURLOPT_HEADER, 1);
curl_setopt($curl, CURLOPT_HTTPPROXYTUNNEL, 1);
curl_setopt($curl, CURLOPT_PROXYTYPE, CURLPROXY_SOCKS5);
curl_setopt($curl, CURLOPT_TIMEOUT, 10);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
$contents = curl_exec($curl);
//Check for errors.
// if (curl_errno($curl)) {
// return new \Exception(curl_error($curl));
// }
curl_close($curl);
return $contents;
}