• ベストアンサー

プログラムからのログイン

こんにちわ。初めて質問します。 PHPを学びはじめて二か月弱の者です。現在、ウェブサイトを巡回するプログラムを作ろうと考えています。 さて質問があります。 IDとパスワードを入力してログインするウェブサイトに対して、 プログラム(ウェブサイトを巡回するプログラム)からログインを行いたいです。 どのようなコードになるでしょうか? なんとなく$_GETや$_POSTが出てきそうな予感がするのですが。…… 勿論IDとパスワードは分かっているものとします。 やり方がわからず、もう二週間くらい悩んでいます。 よろしくお願いします。

質問者が選んだベストアンサー

  • ベストアンサー
noname#244856
noname#244856
回答No.4

要点をまとめるとそんな感じですね。多く書きすぎた気もしますが、中途半端に省略するとかえって疑問が生まれると思ったので詳しく回答させていただきました。 cURLを使う方法がやっぱり一番書きやすくてオススメです。非同期通信に拘るときは fsockopen や stream_socket_client からローレベルな処理を書くときもありますが・・・下記の自作Twitterライブラリでは全ての通信をこれらの関数を使って行っていますね。 GitHub - TwistOAuth https://github.com/Certainist/TwistOAuth ソケットをオープンしている部分 https://github.com/Certainist/TwistOAuth/blob/master/src/TwistExecuter.php#L277 スクレイピング認証(通称「疑似xAuth認証」)でレスポンスを解析している部分 https://github.com/Certainist/TwistOAuth/blob/master/src/TwistExecuter.php#L644

yuko928337
質問者

お礼

とても深い知識をお持ちなのですね。 ありがとうございました。

その他の回答 (3)

noname#244856
noname#244856
回答No.3

連続回答失礼します。 (2番目の回答が「この投稿は、現在サポートで確認中のため、回答は他の方には表示されなくなっております。」となってしまいましたので表示されるまでお待ちください。) 1番目の回答に補足します。 以下の「レスポンス」とは、「レスポンスヘッダー」+「レスポンスボディ」のことを意味し、これらは "\r\n\r\n" で区切るようにして結合されています。 ・fsockopenでつないだときのレスポンス ・stream_socket_clientでつないだときのレスポンス 一方以下のものは「レスポンスボディ」のみを意味します。レスポンスヘッダーは $http_response_header という予約済みの特殊な変数に自動的に配列でセットされています。 ・fopenでつないだときのレスポンス ・file_get_contentsで得られるレスポンス PHP Manual - $http_response_header http://php.net/manual/ja/reserved.variables.httpresponseheader.php cURL利用時のレスポンスも「レスポンスボディ」のみを意味しますが、こちらではcurl_getinfo関数を使ってレスポンスヘッダーの取得を行います。 PHP Manual - curl_getinfo http://php.net/manual/ja/function.curl-getinfo.php

yuko928337
質問者

補足

非常に詳しい解答ありがとうございます。 以下のような感じでよろしいでしょうか? ◆ プログラム(ウェブサイトを巡回するプログラム)からログインするには、「スクリプト」と「サイト」の間で通信を行う必要がある。 ◆ やり方の概要としては。 1. ログインフォームにGETでアクセスしてページ内容を取得する。多くの場合ではその中に不正アクセス対策のトークンが含まれている。この段階でサーバー側からCookieも送られてくる。 2. ログインフォームに必要パラメータを添えてPOSTで送信する。必要パラメータは「不正アクセス対策のトークン」「ユーザーID」「パスワード」その他もろもろ。1で送信されてきたCookieを付加する必要がある。 3. ログインが成功すれば、後は同じCookieを送信し続けるだけで会員専用ページなどの内容を取得することが出来る。 ◆ 上を実現するためのやり方は四つ。 ・ fsockopen関数・stream_socket_client関数を利用する。 ・ fopen関数を利用する。 ・ file_get_contents関数を利用する。 ・ cURL関数群を利用する。 ◆ トークンを抽出するには、以下のやり方がある。 ・正規表現を利用する(正規表現(せいきひょうげん、regular expression)とは、文字列の集合を一つ の文字列で表現する方法の一つである。ウィキペディア) ・ PHPネイティブのDOMを利用する ・ PHPネイティブのDOMとして読み込んだ後SimpleXMLに変換 ・ Simple HTML DOM Parser を利用する

noname#244856
noname#244856
回答No.2

トークンを抽出する方法について。ここでは以下のようなレスポンスボディを得たと仮定します。「token」が不正アクセス対策用のトークンです。 <html> <body> <h1>ログインします</h1> <form action="" method="POST"> <input type="text" name="id" value=""> <input type="password" name="pw" value=""> <input type="hidden" name="token" value="xxxxxxxxxx"> <input type="submit" value="送信"> </form> </body> </html> ● 正規表現を利用する 万能な「正規表現」の力を借りましょう。 Wikipedia - 正規表現 http://ja.wikipedia.org/wiki/%E6%AD%A3%E8%A6%8F%E8%A1%A8%E7%8F%BE サルにもわかる正規表現入門 http://www.mnet.ne.jp/~nakama/ PHP Manual - PCRE正規表現構文 http://php.net/manual/ja/reference.pcre.pattern.syntax.php PHP Manual - preg_match http://php.net/manual/ja/function.preg-match.php Qiita - 私の正規表現に関するポリシー http://qiita.com/mpyw/items/8dd5378cb01c877e1f7b [実装例] PHPの正規表現に使うデリミタは「/」である必要は無く、ここではHTMLタグと重複しない「@」を選択することにします。 [^"]++ は「"」以外の文字の(バックトラック無効な)1回以上の繰り返しを表します。それを ( ) でくくることで、1番目の ( ) として $matches[1] にセットされるようにします。 ちなみに $matches[0] は全体を表します。 $pattern = '@<input type="hidden" name="token" value="([^"]++)">@'; if (!preg_match($pattern, $html, $matches)) { throw new RuntimeException('トークン取得に失敗しました'); } $token = $matches[1]; var_dump($token); ● PHPネイティブのDOMを利用する 正規表現を除けば、最も高速な方法です。 PHP Manual - Document Object Model http://php.net/manual/ja/book.dom.php PHP ARCHIVE - PHP で XML の内容を取得する(DOM, XPath) http://php-archive.net/php/php-dom-xpath/ TECHSCORE - ロケーションパス http://www.techscore.com/tech/XML/XPath/xpath02.html/ 1. DOMDocumentオブジェクトを生成する。 2. loadHTMLメソッドでHTMLとして強引に読み込む。HTMLが厳格に正しく書かれているかどうかの保証は無いので、不正構文で発生するエラーを「@」演算子で抑制する。 3. DOMXPathオブジェクトなどを活用し、目的の値を取りに行く。queryメソッドが基本だが、evaluateメソッドが非常に強力で、使いこなせば複雑な処理をかなり短く書くことが出来る。 [実装例] $xpath = new DOMXPath($dom = new DOMDocument); @$dom->loadHTML($html); if ('' === $token = $xpath->evaluate('string(//input[@name="token"]/@value)')) { throw new RuntimeException('トークン取得に失敗しました'); } var_dump($token); ● PHPネイティブのDOMとして読み込んだ後SimpleXMLに変換 XPathがSimpleXMLElementオブジェクト自体にメソッドとして内包されているなどの点をはじめ、DOMよりもSimpleXMLの方が使いやすく感じる箇所が多いと思います。但し、変換に少々コストがかかりますし、今回のサンプルのようにシンプルな例ではわざわざ使う必要もないでしょう。 PHP Manual - SimpleXML http://php.net/manual/ja/book.simplexml.php ● Simple HTML DOM Parser を利用する 正規表現による一連の操作をラッピングし、もっと使いやすくなったDOMとして提供してくれるライブラリです。本当に使いやすいのですが、C言語コードの拡張としてではなくPHPのコードとして書かれているので、処理は重いです。今回のケースでは不要でしょう。 PHP Simple HTML DOM Parser http://simplehtmldom.sourceforge.net/ PHP Simple HTML DOM Parserの使用方法 http://www.crystal-creation.com/web-appli/technical-information/programming/php/library/simplehtmldom/

noname#244856
noname#244856
回答No.1

スクリプトからログインするためにWebページの取得と解析を行うことを「スクレイピング」と言い、検索するときに役立つので覚えておいてください。以下に概要を示します。「$_GET」「$_POST」といったスーパーグローバル変数は出てきません。これらの変数を使うのはその「スクリプト」と「ユーザー」の間でパラメータを伴う通信を行う場合のみであり、これからその通信を行おうとしているのは「スクリプト」と「サイト」の間でのものです。 1. ログインフォームにGETでアクセスしてページ内容を取得する。多くの場合ではその中に不正アクセス対策のトークンが含まれている。この段階でサーバー側からCookieも送られてくる。 2. ログインフォームに必要パラメータを添えてPOSTで送信する。必要パラメータは「不正アクセス対策のトークン」「ユーザーID」「パスワード」その他もろもろ。1で送信されてきたCookieを付加する必要がある。 3. ログインが成功すれば、後は同じCookieを送信し続けるだけで会員専用ページなどの内容を取得することが出来る。 PHP言語を用いて「スクリプト」と「サイト」の間でHTTP通信を行う手段はいくつかあります。それを説明したいのですが…その前に、HTTP通信についての予備知識が必要なので以下のサイトの内容を先に把握しておいてください。全て分からなくてもいいのでおおまかに。 Studying HTTP (かなり詳しいです) http://www.studyinghttp.net/ とほほのWWW入門 - HTTP入門 (こちらの方がシンプルです) http://www.tohoho-web.com/ex/http.htm 以下、関数などを紹介します。 ● fsockopen関数・stream_socket_client関数 PHP Maual - fsockopen https://php.net/manual/ja/function.fsockopen.php PHP Manual - stream_socket_client https://php.net/manual/ja/function.stream-socket-client.php PHPでHTTP通信を行うための最もローレベルな関数です。これらの関数は「スクリプト」と「サイト」の間で読み書き可能なストリームを確保します。 1. fwrite関数でリクエストヘッダーを送信(書き込む) 2. fgets関数・fread関数・stream_get_contents関数などでレスポンスを受け取る(読み込む) PHP Manual - fwrite http://php.net/manual/ja/function.fwrite.php PHP Manual - fgets http://php.net/manual/ja/function.fgets.php PHP Manual - fread http://php.net/manual/ja/function.fread.php PHP Manual - stream_get_contents http://php.net/manual/ja/function.stream_get_contents.php 最初から読み込めるわけではなく、必要な情報を送信して読み込めるようになるものであると思ってください。 ● fopen関数 PHP Manual - fopen https://php.net/manual/ja/function.fopen.php php.iniの設定で「allow_url_fopen = On」になっている必要がありますが、実はファイルと同じようにサイトに対してもfopen関数でストリームを確保することが出来ます。リクエストヘッダー送信部分は先ほどのローレベルな関数と違って自動化されており、プログラマが記述するのは受け取る処理だけで済みます。自動化された部分を変更したい場合は、stream_context_create関数で「コンテキストリソース」というものを作成して、fopen関数の第4引数に渡す必要があります。CookieやPOSTデータを設定する場合はここをいじる必要がありますね。 PHP Manual - stream_context_create http://php.net/manual/ja/function.stream-context-create.php PHP Manual - HTTPコンテキストオプション http://php.net/manual/ja/context.http.php ● file_get_contents関数 PHP Manual - file_get_contents http://php.net/manual/ja/function.file_get_contents.php 「fopen + stream_get_contents + fclose」の一連の処理を一気に行い、文字列として返してくれる非常に優秀な関数です。こちらにコンテキストリソースを渡したい場合は第3引数に渡します。こちらも同様にphp.iniの設定で「allow_url_fopen = On」になっている必要があります。 ● cURL関数群 Wikipedia - cURL http://ja.wikipedia.org/wiki/CURL PHP Manual - Client URL Library http://php.net/manual/ja/book.curl.php 今まで紹介したものとは全く異なり、広く利用されている「cURL」というライブラリをPHPから利用する手段です。サーバーにcURLがインストールされていないと使用できないという欠点がありますが、実際は多くのレンタルサーバーで利用可能であり、パフォーマンス面でもこちらの方が優れているので利用価値は十分にあるでしょう。流れは以下のようになります。 1. curl_init関数でcURLリソースを生成する。 2. curl_setopt関数で必要なオプションを1つ1つ設定していく。またはcurl_setopt_array関数を利用して連想配列でまとめてオプションを設定する。設定できるオプションに関してはPHPマニュアルのcurl_setopt関数のページに全て記載されている。 3. curl_exec関数でリクエストを実行する。デフォルトではレスポンスがそのまま出力されるが、オプションで「CURLOPT_RETURNTRANSFER」を有効にすることで、出力させずに文字列としてこの関数の返り値にすることが出来る。 先に紹介した3つの方法ではCookieが更新されるたびにコンテキストリソースに再セットし直す必要がありましたが、こちらはクッキーとして利用するファイルのパスを指定するので、最初に1回指定しておくだけで全てそれを使いまわすことが出来ます。・・・非常に便利な関数群なのですが、やはりそのままではこれでも使いにくいので、関数をラップしてクラス化したものを作ってみました。 Qiita - シリアライズ可能なcURLのラッパークラス http://qiita.com/mpyw/items/c65fb4ec4cef80909a47 Cookieなどの情報に関して、serialize関数で保存・unserialize関数で復元できるように工夫しています。「クッキーファイル」を意識する必要が無くなっているので非常に使いやすいと思います。上の記事中にニコニコ動画スクレイピング用の継承クラスをサンプルとして掲載しているので参考にしてください。 なお、トークンをページから抽出する方法については、ここまでで回答が長すぎるので続きを書きます…