PHP による Google reCAPTCHA v2 を用いた検証の例
このページは、PHP で Google reCAPTCHA v2を用いた検証を行う例を記載したページです。
注意
- コードのライセンスは CC0 (クレジット表示不要、改変可、商用可) です。
- 実際に使用する場合には reCAPTCHA に加えて別のデータ (ログインフォームならユーザーIDとパスワード) の確認も必要になるはずですが、reCAPTCHA の試験を目的としたコードとして記載しているためそれらは省いています。
コード (cURLを使用した単純な例)
<?php
define('RECAPTCHA_SITE_KEY', ''); // reCAPTCHAのサイトキー (Google Developer Consoleから取得したものをセットしてください)
define('RECAPTCHA_SECRET_KEY', ''); // reCAPTCHAのシークレットキー (同上)
/**
* reCAPTCHA 検証を行います。(単純な検証)
*
* @param string $gRecapchaResponse $_POST['g-recaptcha-response'] 等から取得できるデータ
* @return array 'success' (成功した場合 true), 'message' (結果メッセージ), 'response' (reCAPTCHA APIからの応答データ(stdClass)) のキーからなる array
*/
function recaptchaSimple($gRecapchaResponse) {
$success = false; // reCAPTCHA が成功した場合 true, それ以外の場合 false
$message = ''; // 結果メッセージ
$response = null; // reCAPTCHA応答データ
// reCAPTCHAデータあり
if ($gRecapchaResponse) {
// reCAPTCHA API用送信データ
$data = array(
'secret' => RECAPTCHA_SECRET_KEY,
'response' => $gRecapchaResponse
);
// cURL から応答データを取得 (cURLを使用できない場合は正常に動作しません)
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "https://www.google.com/recaptcha/api/siteverify");
curl_setopt($curl, CURLOPT_POST, true); // POST送信
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data, '', '&', PHP_QUERY_RFC3986)); // 送信データをセット
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // 証明書検証をしない (環境によって動作しない場合があるため)
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); // curl_exec() 経由で応答データを直接取得できるようにする
$responseString = curl_exec($curl); // 応答データ取得
curl_close($curl);
// 応答取得完了
if ($responseString !== false) {
$response = json_decode($responseString, true);
// JSON解析完了
if ($response !== false) {
// reCAPTCHA検証成功
if (isset($response['success']) && $response['success']) {
$success = true;
$message = 'reCAPTCHAの検証に成功しました。';
}
}
}
}
// 失敗
if (!$success) {
$message = 'reCAPTCHAの検証に失敗しました。';
}
return compact('success', 'message', 'response');
}
function h($value, $encoding = 'UTF-8') { return htmlspecialchars($value, ENT_QUOTES, $encoding); } // HTMlエスケープ出力用
function eh($value, $encoding = 'UTF-8') { echo h($value, $encoding); } // 同上
// reCAPTCHA 検証 (サンプルフォームを POST にしているため POST 時に検証)
if (strtoupper($_SERVER['REQUEST_METHOD']) == 'POST') {
$gRecapchaResponse = filter_input(INPUT_POST, 'g-recaptcha-response'); // reCAPTCHAデータ ( $_POST['g-recaptcha-response'] 等でもよいです )
$result = recaptchaSimple($gRecapchaResponse); // reCAPTCHA 検証
}
// https://developers.google.com/recaptcha/docs/display#auto_render をベースに調整しています。
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>reCAPTCHA demo: Simple page</title>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
</head>
<body>
<form method="POST">
<!-- reCAPTCHAが表示されるエリアです。Developer Consoleで取得したサイトキーを設定します -->
<div class="g-recaptcha" data-sitekey="<?php eh(RECAPTCHA_SITE_KEY) ?>"></div>
<br/>
<input type="submit" value="送信">
</form>
<!-- 結果データの確認 -->
<?php if (isset($result['message'])) { ?>
<p><?php eh($result['message']) ?></p>
<?php } ?>
<?php if (isset($result['response'])) { ?>
<pre class="result"><?php var_dump($result['response']) ?></pre>
<?php } ?>
</body>
</html>
コード (cURL, file_get_contents() 両対応 + メッセージを詳細にした処理)
<?php
define('RECAPTCHA_SITE_KEY', ''); // reCAPTCHAのサイトキー (Google Developer Consoleから取得したものをセットしてください)
define('RECAPTCHA_SECRET_KEY', ''); // reCAPTCHAのシークレットキー (同上)
/**
* reCAPTCHA 検証を行います。
*
* @param string $gRecapchaResponse $_POST['g-recaptcha-response'] 等から取得できるデータ
* @return array 'success' (成功した場合 true), 'message' (結果メッセージ), 'response' (reCAPTCHA APIからの応答データ(stdClass)) のキーからなる array
*/
function recaptcha($gRecapchaResponse) {
$success = false; // reCAPTCHA が成功した場合 true, それ以外の場合 false
$message = ''; // 結果メッセージ
$response = null; // reCAPTCHA応答データ
// reCAPTCHAデータあり
if ($gRecapchaResponse) {
// reCAPTCHA API用送信データ
$data = array(
'secret' => RECAPTCHA_SECRET_KEY,
'response' => $gRecapchaResponse
);
// cURL が使用できる場合 cURL から応答データを取得
if (function_exists('curl_version')) {
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, "https://www.google.com/recaptcha/api/siteverify");
curl_setopt($curl, CURLOPT_POST, true); // POST送信
curl_setopt($curl, CURLOPT_POSTFIELDS, http_build_query($data, '', '&', PHP_QUERY_RFC3986)); // 送信データをセット
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false); // 証明書検証をしない (環境によって動作しない場合があるため)
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); // curl_exec() 経由で応答データを直接取得できるようにする
$responseString = curl_exec($curl); // 応答データ取得
curl_close($curl);
}
// allow_url_fopen が 1 の場合 file_get_contents() から応答データを取得
else if (ini_get('allow_url_fopen') === '1') {
$context = stream_context_create(array(
'http' => array(
'method' => 'POST', // POST送信
'header' => 'Content-Type: application/x-www-form-urlencoded',
'content' => http_build_query($data, '', '&', PHP_QUERY_RFC3986) // 送信データをセット
),
'ssl' => array(
'verify_peer' => false, // 証明書検証をしない (環境によって動作しない場合があるため)
'verify_peer_name' => false, // ピア名検証をしない (同上)
)
));
$responseString = @file_get_contents('https://www.google.com/recaptcha/api/siteverify', false, $context); // 応答データ取得
}
else {
// どちらも使えない場合はサーバー環境の見直しが必要かもしれません…
$message = 'reCAPTCHA APIに接続できませんでした。';
}
// 応答取得完了
if ($responseString !== false) {
$response = json_decode($responseString, true);
// JSON解析完了
if ($response !== false) {
// reCAPTCHA検証成功
if (isset($response['success']) && $response['success']) {
$success = true;
$message = 'reCAPTCHAの検証に成功しました。';
}
// 失敗
else {
$message = 'reCAPTCHAの検証に失敗しました。';
if (isset($response['error-codes']) && is_array($response['error-codes'])) {
$messageArray = array();
foreach ($response['error-codes'] as $code) {
switch ($code) {
case 'missing-input-secret':
$messageArray[] = 'シークレットキーが指定されていません。';
break;
case 'invalid-input-secret':
$messageArray[] = '有効なシークレットキーではありません。';
break;
case 'missing-input-response':
$messageArray[] = 'reCAPTCHAの入力がされていません。';
break;
case 'invalid-input-response':
$messageArray[] = '有効なreCAPTCHAの入力ではありません。';
break;
case 'bad-request':
$messageArray[] = '不正なリクエストです。';
break;
case 'timeout-or-duplicate':
$messageArray[] = '検証に時間がかかりすぎているか、検証データが重複しています。';
break;
}
}
if ($messageArray) $message .= implode('', $messageArray);
}
}
}
else {
$message = 'reCAPTCHAの応答データが正常に取得できませんでした。';
}
}
else if (!$message) {
$message = 'reCAPTCHAの応答データが取得できませんでした。';
}
}
else {
$message = 'reCAPTCHAの検証に失敗しました。reCAPTCHAの入力がされていません。';
}
return compact('success', 'message', 'response');
}
function h($value, $encoding = 'UTF-8') { return htmlspecialchars($value, ENT_QUOTES, $encoding); } // HTMlエスケープ出力用
function eh($value, $encoding = 'UTF-8') { echo h($value, $encoding); } // 同上
// reCAPTCHA 検証 (サンプルフォームを POST にしているため POST 時に検証)
if (strtoupper($_SERVER['REQUEST_METHOD']) == 'POST') {
$gRecapchaResponse = filter_input(INPUT_POST, 'g-recaptcha-response'); // reCAPTCHAデータ ( $_POST['g-recaptcha-response'] でもよいです )
$result = recaptcha($gRecapchaResponse); // reCAPTCHA 検証
}
// https://developers.google.com/recaptcha/docs/display#auto_render をベースに調整しています。
?>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>reCAPTCHA demo: Simple page</title>
<script src="https://www.google.com/recaptcha/api.js" async defer></script>
</head>
<body>
<form method="POST">
<!-- reCAPTCHAが表示されるエリアです。Developer Consoleで取得したサイトキーを設定します -->
<div class="g-recaptcha" data-sitekey="<?php eh(RECAPTCHA_SITE_KEY) ?>"></div>
<br/>
<input type="submit" value="送信">
</form>
<!-- 結果データの確認 -->
<?php if (isset($result['message'])) { ?>
<p><?php eh($result['message']) ?></p>
<?php } ?>
<?php if (isset($result['response'])) { ?>
<pre class="result"><?php var_dump($result['response']) ?></pre>
<?php } ?>
</body>
</html>
結果
※下記は画像のためクリックしても動作しません。