私の答えは、フォーム認証にのみ適用されます (これは、認証の最も一般的な形式です)。
基本的に、Web サイトを閲覧するときは、その Web サイトで「セッション」を開きます。Web サイトにログインすると、セッションが「認証」され、それに基づいてあらゆる場所へのアクセスが許可されます。
ブラウザは、Cookie に保存されたセッション ID のおかげで、サーバーへの対応するセッションを識別します。
そのため、ログイン ページを参照してから、その過程で Cookie を送信することを忘れずに、必要なページを参照する必要があります。Cookie は、閲覧するすべてのページ間のリンクです。
私は実際にあなたが少し前にしたのと同じ問題に直面し、このクッキーのことを覚えておく必要なしにそれを行うためのクラスを書きました.
クラスをざっと見てください。それは重要ではありませんが、以下の例をよく見てください。CSRF 保護を実装するフォームを送信できます。
このクラスには、基本的に次の機能があります。 - CSRF トークン ベースの保護に準拠 - 「共通」ユーザー エージェントを送信します。一部の Web サイトは、ユーザー エージェントと通信しないクエリを拒否します - Referrer ヘッダーを送信します。一部の Web サイトは、リファラーと通信しないクエリを拒否します (これは別の csrf 対策です) - 呼び出し間で Cookie を保存します
ファイル: WebClient.php
<?php
/**
* Webclient
*
* Helper class to browse the web
*
* @author Bgi
*/
class WebClient
{
private $ch;
private $cookie = '';
private $html;
public function Navigate($url, $post = array())
{
curl_setopt($this->ch, CURLOPT_URL, $url);
curl_setopt($this->ch, CURLOPT_COOKIE, $this->cookie);
if (!empty($post)) {
curl_setopt($this->ch, CURLOPT_POST, TRUE);
curl_setopt($this->ch, CURLOPT_POSTFIELDS, $post);
}
$response = $this->exec();
if ($response['Code'] !== 200) {
return FALSE;
}
//echo curl_getinfo($this->ch, CURLINFO_HEADER_OUT);
return $response['Html'];
}
public function getInputs()
{
$return = array();
$dom = new DOMDocument();
@$dom->loadHtml($this->html);
$inputs = $dom->getElementsByTagName('input');
foreach($inputs as $input)
{
if ($input->hasAttributes() && $input->attributes->getNamedItem('name') !== NULL)
{
if ($input->attributes->getNamedItem('value') !== NULL)
$return[$input->attributes->getNamedItem('name')->value] = $input->attributes->getNamedItem('value')->value;
else
$return[$input->attributes->getNamedItem('name')->value] = NULL;
}
}
return $return;
}
public function __construct()
{
$this->init();
}
public function __destruct()
{
$this->close();
}
private function init()
{
$this->ch = curl_init();
curl_setopt($this->ch, CURLOPT_USERAGENT, "Mozilla/6.0 (Windows NT 6.2; WOW64; rv:16.0.1) Gecko/20121011 Firefox/16.0.1");
curl_setopt($this->ch, CURLOPT_FOLLOWLOCATION, TRUE);
curl_setopt($this->ch, CURLOPT_MAXREDIRS, 5);
curl_setopt($this->ch, CURLINFO_HEADER_OUT, TRUE);
curl_setopt($this->ch, CURLOPT_HEADER, TRUE);
curl_setopt($this->ch, CURLOPT_AUTOREFERER, TRUE);
}
private function exec()
{
$headers = array();
$html = '';
ob_start();
curl_exec($this->ch);
$output = ob_get_contents();
ob_end_clean();
$retcode = curl_getinfo($this->ch, CURLINFO_HTTP_CODE);
if ($retcode == 200) {
$separator = strpos($output, "\r\n\r\n");
$html = substr($output, $separator);
$h = trim(substr($output,0,$separator));
$lines = explode("\n", $h);
foreach($lines as $line) {
$kv = explode(':',$line);
if (count($kv) == 2) {
$k = trim($kv[0]);
$v = trim($kv[1]);
$headers[$k] = $v;
}
}
}
// TODO: it would deserve to be tested extensively.
if (!empty($headers['Set-Cookie']))
$this->cookie = $headers['Set-Cookie'];
$this->html = $html;
return array('Code' => $retcode, 'Headers' => $headers, 'Html' => $html);
}
private function close()
{
curl_close($this->ch);
}
}
どうやって使うの?
この例では、Web サイトにログインし、ファイルをアップロードするためのフォームを含むページを参照してから、ファイルをアップロードします。
<?php
require_once('WebClient.php');
$url = 'http://example.com/administrator/index.php'; // This a Joomla admin
$wc = new WebClient();
$page = $wc->Navigate($url);
if ($page === FALSE) {
die('Failed to load login page.');
}
echo('Logging in...');
$post = $wc->getInputs();
$post['username'] = $username;
$post['passwd'] = $passwd;
$page = $wc->Navigate($url, $post);
if ($page === FALSE) {
die('Failed to post credentials.');
}
echo('Initializing installation...');
$page = $wc->Navigate($url.'?option=com_installer');
if ($page === FALSE) {
die('Failed to access installer.');
}
echo('Installing...');
$post = $wc->getInputs();
$post['install_package'] = '@'.$file; // The @ specifies we are sending a file
$page = $wc->Navigate($url.'?option=com_installer&view=install', $post);
if ($page === FALSE) {
die('Failed to upload file.');
}
echo('Done.');
Navigate() メソッドは、閲覧したページの HTML コンテンツまたは FALSE を返します。
ああ、最後に 1 つ: HTML の解析に正規表現を使用しないでください。これは誤りです。それについては、伝説的な StackOverflow の回答があります。こちらを参照してください。