PHP 卷曲和 Cookie
Posted
技术标签:
【中文标题】PHP 卷曲和 Cookie【英文标题】:PHP Curl And Cookies 【发布时间】:2012-10-04 19:57:32 【问题描述】:我在 php Curl 和 cookie 身份验证方面遇到了一些问题。
我有一个文件Connector.php,它对另一台服务器上的用户进行身份验证并返回当前用户的cookie。
问题是我想使用 curl 对数千个用户进行身份验证,但它一次只为一个用户进行身份验证和保存 COOKIES。
connector.php 的代码是这样的:
<?php
if(!count($_REQUEST))
die("No Access!");
//Core Url For Services
define ('ServiceCore', 'http://example.com/core/');
//Which Internal Service Should Be Called
$path = $_GET['service'];
//Service To Be Queried
$url = ServiceCore.$path;
//Open the Curl session
$session = curl_init($url);
// If it's a GET, put the GET data in the body
if ($_GET['service'])
//Iterate Over GET Vars
$postvars = '';
foreach($_GET as $key=>$val)
if($key!='service')
$postvars.="$key=$val&";
curl_setopt ($session, CURLOPT_POST, true);
curl_setopt ($session, CURLOPT_POSTFIELDS, $postvars);
//Create And Save Cookies
$tmpfname = dirname(__FILE__).'/cookie.txt';
curl_setopt($session, CURLOPT_COOKIEJAR, $tmpfname);
curl_setopt($session, CURLOPT_COOKIEFILE, $tmpfname);
curl_setopt($session, CURLOPT_HEADER, false);
curl_setopt($session, CURLOPT_RETURNTRANSFER, true);
curl_setopt($session, CURLOPT_FOLLOWLOCATION, true);
// EXECUTE
$json = curl_exec($session);
echo $json;
curl_close($session);
?>
认证过程如下:
-
用户输入用户名和密码:
Connector.php?service=logon&user_name=user32&user_pass=123
Connector.php?service=logosessionInfo
根据之前使用登录服务保存的 cookie 返回有关用户的信息。
问题是这段代码为每个用户将cookie保存在一个文件中,无法处理多个用户身份验证。
【问题讨论】:
我通过为具有唯一 PHPSESSID 的不同用户创建不同的 cookie 文件解决了我的问题。$tmpfname = dirname(__FILE__).'/'.$_COOKIE['PHPSESSID'].'.txt';
如果有很多用户是个好主意吗?
否 如果您有很多用户,这很糟糕。它会导致 apache 服务器崩溃。我用 apache 代理解决了这个问题。并删除了我所有的 CURL 代码。
【参考方案1】:
首先使用 tempnam() 函数创建临时 cookie:
$ckfile = tempnam ("/tmp", "CURLCOOKIE");
然后执行 curl init 将 cookie 保存为临时文件:
$ch = curl_init ("http://uri.com/");
curl_setopt ($ch, CURLOPT_COOKIEJAR, $ckfile);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
$output = curl_exec ($ch);
或者使用存储在临时文件中的cookie访问页面:
$ch = curl_init ("http://somedomain.com/cookiepage.php");
curl_setopt ($ch, CURLOPT_COOKIEFILE, $ckfile);
curl_setopt ($ch, CURLOPT_RETURNTRANSFER, true);
$output = curl_exec ($ch);
这将初始化页面的cookie:
curl_setopt ($ch, CURLOPT_COOKIEFILE, $ckfile);
【讨论】:
如果有大量用户尝试同时访问该页面,而您已经在 /tmp 中有一些文件,该怎么办? PHP 文档说: 注意:如果 PHP 无法在指定的 dir 参数中创建文件,它将回退到系统默认值。在 NTFS 上,如果指定的目录包含超过 65534 个文件,也会发生这种情况。 如果存储时间超过 24 小时,请删除 cookie 文件。为 $ckfile 单独存储一个 cookie 数据,以检查 /tmp 中的所有文件。 3 年后,你仍然是像我这样的非 PHP 人士的救命稻草。在浏览了一堆 *** 答案后,这里有一个很好的解释。【参考方案2】:在处理类似问题时,我在结合了我在网络上遇到的大量资源并添加了我自己的 cookie 处理后创建了以下函数。希望这对其他人有用。
function get_web_page( $url, $cookiesIn = '' )
$options = array(
CURLOPT_RETURNTRANSFER => true, // return web page
CURLOPT_HEADER => true, //return headers in addition to content
CURLOPT_FOLLOWLOCATION => true, // follow redirects
CURLOPT_ENCODING => "", // handle all encodings
CURLOPT_AUTOREFERER => true, // set referer on redirect
CURLOPT_CONNECTTIMEOUT => 120, // timeout on connect
CURLOPT_TIMEOUT => 120, // timeout on response
CURLOPT_MAXREDIRS => 10, // stop after 10 redirects
CURLINFO_HEADER_OUT => true,
CURLOPT_SSL_VERIFYPEER => true, // Validate SSL Certificates
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_COOKIE => $cookiesIn
);
$ch = curl_init( $url );
curl_setopt_array( $ch, $options );
$rough_content = curl_exec( $ch );
$err = curl_errno( $ch );
$errmsg = curl_error( $ch );
$header = curl_getinfo( $ch );
curl_close( $ch );
$header_content = substr($rough_content, 0, $header['header_size']);
$body_content = trim(str_replace($header_content, '', $rough_content));
$pattern = "#Set-Cookie:\\s+(?<cookie>[^=]+=[^;]+)#m";
preg_match_all($pattern, $header_content, $matches);
$cookiesOut = implode("; ", $matches['cookie']);
$header['errno'] = $err;
$header['errmsg'] = $errmsg;
$header['headers'] = $header_content;
$header['content'] = $body_content;
$header['cookies'] = $cookiesOut;
return $header;
【讨论】:
非常有用的傻瓜代码。有用。谢谢你。如果人们想要 HTTP 状态代码,请使用以下语法:$header['http_code']; @Doug,我在here 中检查了您的代码的正则表达式#Set-Cookie:\\s+(?<cookie>[^=]+=[^;]+)#m
,正则表达式引擎将这部分\\s+
解释为:\` matches the character \ literally
s+` 匹配字符 s 字面意思(区分大小写)——这不是正则表达式的错误,不应该是\s+
(只有一个反斜杠)吗?
@Igor,\\ 是因为在 PHP the \ is viewed as an escape character 中处理字符串时。因此,您需要两个斜杠来等于评估字符串中的一个斜杠(然后将其用于 RegEx 匹配)。从 RegEx 的角度来看,您是正确的,我只想要一个斜杠。【参考方案3】:
上述解决方案,即使具有唯一的 CookieFile 名称,也会在规模上造成很多问题。
我们必须使用此解决方案提供大量身份验证,并且由于高文件读写操作,我们的服务器出现故障。
解决方案是使用 Apache 反向代理并完全忽略 CURL 请求。
如何在 Apache 上使用 Proxy 的详细信息可以在这里找到: https://httpd.apache.org/docs/2.4/howto/reverse_proxy.html
【讨论】:
【参考方案4】:在这里您可以找到一些关于 cURL 和 cookie http://docstore.mik.ua/orelly/webprog/pcook/ch11_04.htm 的有用信息。
你也可以像函数一样使用这个做得好的方法https://github.com/alixaxel/phunction/blob/master/phunction/Net.php#L89:
function CURL($url, $data = null, $method = 'GET', $cookie = null, $options = null, $retries = 3)
$result = false;
if ((extension_loaded('curl') === true) && (is_resource($curl = curl_init()) === true))
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_FAILONERROR, true);
curl_setopt($curl, CURLOPT_AUTOREFERER, true);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
if (preg_match('~^(?:DELETE|GET|HEAD|OPTIONS|POST|PUT)$~i', $method) > 0)
if (preg_match('~^(?:HEAD|OPTIONS)$~i', $method) > 0)
curl_setopt_array($curl, array(CURLOPT_HEADER => true, CURLOPT_NOBODY => true));
else if (preg_match('~^(?:POST|PUT)$~i', $method) > 0)
if (is_array($data) === true)
foreach (preg_grep('~^@~', $data) as $key => $value)
$data[$key] = sprintf('@%s', rtrim(str_replace('\\', '/', realpath(ltrim($value, '@'))), '/') . (is_dir(ltrim($value, '@')) ? '/' : ''));
if (count($data) != count($data, COUNT_RECURSIVE))
$data = http_build_query($data, '', '&');
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, strtoupper($method));
if (isset($cookie) === true)
curl_setopt_array($curl, array_fill_keys(array(CURLOPT_COOKIEJAR, CURLOPT_COOKIEFILE), strval($cookie)));
if ((intval(ini_get('safe_mode')) == 0) && (ini_set('open_basedir', null) !== false))
curl_setopt_array($curl, array(CURLOPT_MAXREDIRS => 5, CURLOPT_FOLLOWLOCATION => true));
if (is_array($options) === true)
curl_setopt_array($curl, $options);
for ($i = 1; $i <= $retries; ++$i)
$result = curl_exec($curl);
if (($i == $retries) || ($result !== false))
break;
usleep(pow(2, $i - 2) * 1000000);
curl_close($curl);
return $result;
并将其作为$cookie
参数传递:
$cookie_jar = tempnam('/tmp','cookie');
【讨论】:
【参考方案5】:您可以使用 curl opt 指定 cookie 文件。您可以为每个用户使用一个唯一的文件。
curl_setopt( $curl_handle, CURLOPT_COOKIESESSION, true );
curl_setopt( $curl_handle, CURLOPT_COOKIEJAR, uniquefilename );
curl_setopt( $curl_handle, CURLOPT_COOKIEFILE, uniquefilename );
处理它的最佳方法是将您的请求逻辑粘贴到 curl 函数中,并将唯一的文件名作为参数传递。
function fetch( $url, $z=null )
$ch = curl_init();
$useragent = isset($z['useragent']) ? $z['useragent'] : 'Mozilla/5.0 (Windows NT 6.1; WOW64; rv:10.0.2) Gecko/20100101 Firefox/10.0.2';
curl_setopt( $ch, CURLOPT_URL, $url );
curl_setopt( $ch, CURLOPT_RETURNTRANSFER, true );
curl_setopt( $ch, CURLOPT_AUTOREFERER, true );
curl_setopt( $ch, CURLOPT_FOLLOWLOCATION, true );
curl_setopt( $ch, CURLOPT_POST, isset($z['post']) );
if( isset($z['post']) ) curl_setopt( $ch, CURLOPT_POSTFIELDS, $z['post'] );
if( isset($z['refer']) ) curl_setopt( $ch, CURLOPT_REFERER, $z['refer'] );
curl_setopt( $ch, CURLOPT_USERAGENT, $useragent );
curl_setopt( $ch, CURLOPT_CONNECTTIMEOUT, ( isset($z['timeout']) ? $z['timeout'] : 5 ) );
curl_setopt( $ch, CURLOPT_COOKIEJAR, $z['cookiefile'] );
curl_setopt( $ch, CURLOPT_COOKIEFILE, $z['cookiefile'] );
$result = curl_exec( $ch );
curl_close( $ch );
return $result;
我用它来快速抓取。它需要 url 和一个选项数组。
【讨论】:
【参考方案6】:您可以使用CURLOPT_COOKIEFILE
和CURLOPT_COOKIEJAR
为每个用户定义不同的cookie。为每个用户制作不同的文件,这样每个用户都可以在远程服务器上拥有自己的基于 cookie 的会话。
【讨论】:
当这个页面被大量用户(超过一万)使用时怎么办?这对服务器来说不是很大的负载吗?以上是关于PHP 卷曲和 Cookie的主要内容,如果未能解决你的问题,请参考以下文章