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サイトにアクセスして、そのレスポンスを取得する関数としては下記のように記述できます。
先に紹介したサイトのサンプルソースをほぼそのままですが。
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情報のみを取得する処理も加えてみます。)
// 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」は、下記のような感じで定数として指定している想定です。
// 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でのアクセスが必要なサイトにアクセスしたときに表示されるエラーの一例は、以下のようになります。
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を指定してみるといいのではないか、と思います。
この記事が参考になったと思いましたらソーシャルメディアで共有していただけると嬉しいです!
関連記事
-
-
PHPでスクレイピング。phpQueryとphp-simple-html-dom-parserの比較と設置方法
「PHP スクレイピング」で検索すると「phpQuery」ばかりヒットするが、10年以上も放置されている。なので今も開発が続いている「PHP Simple HTML DOM Parser」をオススメする。
-
-
路線・駅検索のために緯度経度からPHPで2点間の距離を計算する処理解説
路線・駅検索の仕組みの構築は大変。それを簡易に実装するために緯度経度を元に距離計算をする仕組みを考案。まずは2点間の距離を計算する仕組みを解説し、距離計算にまつわる関連技術も紹介。
-
-
GMOペイメントゲートウェイのjava.io.IOExceptionのエラー
ECCUBEの決済でGMOペイメントゲートウェイのモジュールを使ってテスト決済を行った場合の不具合、java.io.IOExceptionと言うエラーの原因と対策方法の解説です。
-
-
配列の値をテキスト表示する際に「、」でつなげるときの処理方法の一例
配列の値を「、」でつないで出力する際、単純にforeachで繰り返し処理をすると「イヌ、サル、キジ、」となるが文字列最後の「、」を出力しない方法を3つ解説している。
-
-
ECCUBEを開発環境から本番ドメインに変更でエラーが・パス変更について
レンタルサーバでサーバ会社から割り当てられたURLで開発し、本番公開時にドメインを当てたらエラーが!そんな場合の対処方法の解説。対処方法は簡単ですが管理画面からは対応不可。
-
-
PHPで APIにアクセスする際などに使用する cURLのサンプルプログラム
PHPのcURLを使用して各種APIにアクセスするサンプルプログラムを作成し、その処理を解説。カオナビAPIのみならず、他の多くのAPIにアクセスする際にも使用できる。
-
-
PHPで配列の値をダブルクオーテーションで囲んでimplodeでカンマ区切りにする方法
PHPで配列の値を、preg_replace関数でクォーテーションで囲み、implode関数で「,(カンマ)」で区切ってテキスト化する方法。この方法であれば配列が空でも分岐の処理は必要なし!
-
-
フォルダを指定してファイルのパーミッションを変更するプログラム
フォームからフォルダ、パーミッションを指定しパーミッションを変更するサンプルプログラムの解説です。
-
-
cURLを利用する際の注意点「
&」があるURLは「”」で囲むcURLでURLはダブルクォーテーションで囲む。LinuxでもWindowsでもコマンドでは「&」は意味を持つ文字のためエラー原因になる。クォーテーションは常につけておく方が無難。
-
-
SEO対策用タイトル、ディスクリプションの文字数カウントツール
SEO対策に使える文字数カウントツールで文字数の条件の説明も行っています。
