PHPのcURLでAPIやWebサイトへのアクセス方法。file_get_contentsとの比較
2020/02/08
PHPの cURLで APIや Webサイトにアクセスする方法
file_get_contentsもあるけど cURLの方が細かな制御が可能
PHPのプログラムの処理の一つとして
・APIにアクセスをする
・Webスクレイピングをする
という場合には、PHPのプログラムから Webサイトにアクセスをする必要があります。
そんなときに「cURL(カール)」を使って Webサイトにアクセスする方法を解説します。
PHPから Webサイトにアクセスする場合は「file_get_contents()」を使うと簡単にページの情報を取得できますので便利です。
ですが、下記のサイトにあるように、「file_get_contents()」では厳密な制御が難しいという難点があります。
https://qiita.com/shinkuFencer/items/d7546c8cbf3bbe86dab8
個人的なツールを作成するときには file_get_contents()でも問題なくても、Webサービスを作成する場合にはトラブルにつながる可能性があるわけです。
そんなわけで、PHPから Webサイトにアクセスするときは、cURLを利用することをおすすめします。
cURLで Webサイトから情報を取得する関数の一例
cURLを利用して Webサイトにアクセスして、そのレスポンスを取得する関数としては下記のように記述できます。
先に紹介したサイトのサンプルソースをほぼそのままですが。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
public function getApiDataCurl($url){ $option = [ CURLOPT_RETURNTRANSFER => true, // 文字列として返す CURLOPT_TIMEOUT => 30, // タイムアウト時間 ]; $ch = curl_init($url); curl_setopt_array($ch, $option); $body = curl_exec($ch); $info = curl_getinfo($ch); $errorNo = curl_errno($ch); $errorMsg = curl_error($ch); // 「CURLE_OK」以外はエラーなのでエラー情報を返す if ($errorNo !== CURLE_OK) { // 詳しくエラーハンドリングしたい場合はerrorNoで確認 // タイムアウトの場合はCURLE_OPERATION_TIMEDOUT return $errorNo . " : " . $errorMsg; } // 200以外のステータスコードは失敗なのでそのステータスコードを返す if ($info['http_code'] !== 200) { return $info['http_code']; } $responseArray = json_decode($body, true); // JSON を配列に変換 return $responseArray; } |
アクセスする URLをパラメータとして付与して関数を呼び出します。
JSON形式で結果を返してくれる APIにアクセスしたと想定すると、結果を配列で取り出すことができる、という仕組みのものです。
SSLでアクセス、UserAgentが必要なページへの対応を行った cURLの関数
ですが、このサンプルソースでは、2つの条件では正常に情報を取得することが出来ません。
・SSLでアクセスする必要があるページ
・UserAgentを必要とするページ
最近は、多くのサイトが SSLに対応してきまして、SSLでのみアクセス可能なサイトも増えてきました。
そのため、SSLでのアクセス対応は必須といえます。
また、自動プログラムによるアクセスやスクレイピングされることの対策として、UserAgentが設定されていない状態でのアクセスを拒否するサイトも存在しています。
というわけで、この 2つを対策してみましょう。
また、先のソースは APIにアクセスして JSONをレスポンスとして取得する想定でしたが、単純に HTMLを取得する場合もあるでしょうから、それを分岐した処理も加えてみます。(さらに、header情報のみを取得する処理も加えてみます。)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
// APIを呼び出し、結果を受け取る処理(URLにアクセスしその結果を取得する処理) // $url :APIの URI(アクセスする URL) // $responseType:受け取る結果のタイプ(header、html、json) public function getApiDataCurl($url, $responseType = "html" ){ if ( $responseType == "header" ) { $option = [ CURLOPT_RETURNTRANSFER => true, // 文字列として返す CURLOPT_TIMEOUT => 30, // タイムアウト時間 CURLOPT_HEADER => true, CURLOPT_NOBODY => true, CURLOPT_SSL_VERIFYPEER => false, // サーバ証明書の検証をしない ]; } else { $option = [ CURLOPT_RETURNTRANSFER => true, // 文字列として返す CURLOPT_TIMEOUT => 30, // タイムアウト時間 CURLOPT_SSL_VERIFYPEER => false, // サーバ証明書の検証をしない CURLOPT_USERAGENT => USER_AGENT_TEXT, // UserAgentを指定 ]; } $ch = curl_init($url); curl_setopt_array($ch, $option); $body = curl_exec($ch); $info = curl_getinfo($ch); $errorNo = curl_errno($ch); $errorMsg = curl_error($ch); // 「CURLE_OK」以外はエラーなのでエラー情報を返す if ($errorNo !== CURLE_OK) { // 詳しくエラーハンドリングしたい場合はerrorNoで確認 // タイムアウトの場合はCURLE_OPERATION_TIMEDOUT return $errorNo . " : " . $errorMsg; } // 200以外のステータスコードは失敗なのでそのステータスコードを返す if ($info['http_code'] !== 200) { return $info['http_code']; } // headerのみ取得 if($responseType == "header") { $responseArray = explode("\n", $body); // 行に分割 $responseArray = array_map('trim', $responseArray); // 各行にtrim()をかける $responseArray = array_filter($responseArray, 'strlen'); // 文字数が0の行を取り除く $responseArray = array_values($responseArray); // キーを連番に振りなおす // HTMLの本体を取得 } elseif($responseType == "html"){ $responseArray = $body; // JSONで取得した情報を配列に変換して取得 } else { $responseArray = json_decode($body, true); // JSON を配列に変換 } return $responseArray; } |
上記の「CURLOPT_USERAGENT」のパラメータとして指定している「USER_AGENT_TEXT」は、下記のような感じで定数として指定している想定です。
1 2 |
// UserAgent define("USER_AGENT_TEXT", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/79.0.3945.88 Safari/537.36"), |
SSLでのアクセスが必要なサイトにアクセスしたときのエラー
SSLでのアクセスが必要なサイトにアクセスしたときに表示されるエラーの一例は、以下のようになります。
1 2 3 |
77 : error setting certificate verify locations: CAfile: C:\xampp\apache\bin\curl-ca-bundle.crt CApath: none |
SSLでサイトにアクセスする際は、サーバ証明書のチェックを行いますが、上記のエラーは「サーバ証明書がありません」というものです。
そのため、先の設定では、SSLでアクセスする際もサーバ証明書のチェックを行わない、とするものです。
ですが、サーバ証明書を設置することで本来の SSLアクセスであるサーバ証明書をチェックしながら正常にアクセスをする方法もあります。
詳しくは下記の記事などが参考になるかと思います。
https://www.softel.co.jp/blogs/tech/archives/4026
UserAgentがない状態でサイトにアクセスしたときのエラー
UserAgentがない状態でサイトにアクセスしたときのエラーは、サイトによってさまざまです。
そのため、こんなエラーが出ますという表現は意味を持ちませんが、この記事を書くきっかけとなったサイトでは下記のようなエラーがでていました。
上記のエラーは、「サポート外のブラウザです」ということですので、正しく見ることができるブラウザの UserAgentを指定してみるといいのではないか、と思います。
GoogleAdwords
GoogleAdwords
この記事が参考になったと思いましたらソーシャルメディアで共有していただけると嬉しいです!
関連記事
-
-
PHPのデバッグで使う print_r、var_dump、var_exportの動作の違い
PHPのデバッグ等で変数や配列の中身を確認するために使用する関数print_r、var_dump、var_exportの動作の違い、仕様の違いについて確認した。var_exportがオススメ。
-
-
JSON形式の値を配列形式に変換・PHPでは json_decode()、json_encode()
JSONとは「JavaScript Object Notation」の略でテキストベースのデータフォーマット。JSONの値をPHPで配列に変換するWebツールの紹介とその処理「json_encode()」「json_decode()」関数の解説。
-
-
ファイル変更だけ!ECCUBEの本番から開発環境をコピーする手順を解説
ECCUBEを本番から開発環境をコピーする際の手順を解説。PGMメンテに必要な開発環境を構築する手順を解説。ECCUBEの仕組みは簡単なので作業は5分ほど。
-
-
ECCUBEでアップロードできない。upload_max_filesizeを設定する場所
テンプレートをアップロードする際に発生するエラー「テンプレートファイルがアップロードされていません」の対処方法。これはファイル容量の制限に引っかかっています。
-
-
乱数発生器(パスワード生成サービス)がバージョンアップで高速化!
乱数やパスワードを生成する乱数発生器を高速化!重複しない10桁、20桁の文字列を10万件、20万件と生成することも可能!イベントのキャンペーンのシリアルコードなどにも利用可能!
-
-
XML形式の値を配列形式に変換・PHPでは simplexml_load_string()
XMLとは「Extensible Markup Language」の略でテキストベースのデータフォーマット。XMLをPHPで配列に変換するWebツールの紹介とその処理「simplexml_load_string()」関数についての解説。
-
-
ECCUBEの注文完了画面注文番号と商品情報を編集するCRITEO(クリテオ)タグを編集
ECCUBEの注文完了画面にクリテオのタグを編集する方法を紹介。標準機能では完了画面に注文IDや購入商品の情報を渡さないため改修が必要です。
-
-
ECCUBEでカード決済NGの受注情報をマイページ購入履歴に表示しない方法解説
ECCUBEでカード決済に失敗しても購入履歴一覧に注文情報(受注情報)が表示される問題への対処方法を解説。受注情報レコードの作成の流れとステイタスについても解説。
-
-
連想配列のキーも値もまとめてhtmlspecialchars()でサニタイズする関数の作成解説
PHPの配列・連想配列のキーと値をまとめてhtmlspecialchars()関数でサニタイズ(無害化、無毒化)を行う関数を作成。連想配列のキーはarray_map()関数でのサニタイズは無理。
-
-
PHPのスクレイピングライブラリ「PHP Simple HTML DOM Parser」の使い方
PHPのスクレイピングライブラリ「PHP Simple HTML DOM Parser」の使い方を解説。要素を取得する方法、そこから属性を取得する方法を解説。また、マニュアルにはない注意点なども解説。