wordpressから、Firebase functionsで作ったホットスポットにPOSTでデータを取りに行った。
トークンをPOSTしたら、セッションIDと所属コードを返して来る。
所属コードを、ローカルストレージに入れて、各ページを表示する。
functions.phpで、Firebase functionsのURLへデータを取りに行ったのですが、記述が悪いのか、変数をpage.php側でechoすると、OKとだけ出る。
Firebase側のJavascriptでは、OKと出るような記載はない。
ただ、エラーになっていて、エラーの内容は、非同期になっていない時のエラー文でした。
WordPress と Firebase Functions の連携で非同期処理の問題が発生しているようですね。状況を整理して、解決方法を提案します。
問題の原因
「OK」とだけ表示されるのは、おそらく以下のいずれかが原因です:
-
レスポンスボディの取得ミス -
wp_remote_retrieve_body()を使っていない - 非同期処理の待機不足 - Firebase Functionsの応答を待たずに処理が終了している
- エラーハンドリング不足 - エラーレスポンスを適切にキャッチできていない
解決方法
functions.php の正しい書き方
<?php
function get_firebase_data($token) {
$firebase_url = 'https://YOUR-REGION-YOUR-PROJECT.cloudfunctions.net/YOUR-FUNCTION';
// POSTリクエストを送信
$response = wp_remote_post($firebase_url, array(
'method' => 'POST',
'timeout' => 45, // タイムアウトを長めに設定
'headers' => array(
'Content-Type' => 'application/json',
),
'body' => json_encode(array(
'token' => $token
))
));
// エラーチェック
if (is_wp_error($response)) {
error_log('Firebase request error: ' . $response->get_error_message());
return array('error' => $response->get_error_message());
}
// ステータスコード確認
$status_code = wp_remote_retrieve_response_code($response);
if ($status_code !== 200) {
error_log('Firebase returned status: ' . $status_code);
return array('error' => 'HTTP Error: ' . $status_code);
}
// ボディを取得してデコード(ここが重要!)
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
if (json_last_error() !== JSON_ERROR_NONE) {
error_log('JSON decode error: ' . json_last_error_msg());
return array('error' => 'Invalid JSON response');
}
return $data;
}
// ショートコードやAJAXで使用する例
function handle_firebase_request() {
$token = isset($_POST['token']) ? sanitize_text_field($_POST['token']) : '';
if (empty($token)) {
wp_send_json_error(array('message' => 'Token is required'));
}
$result = get_firebase_data($token);
if (isset($result['error'])) {
wp_send_json_error($result);
} else {
wp_send_json_success($result);
}
}
add_action('wp_ajax_get_firebase_data', 'handle_firebase_request');
add_action('wp_ajax_nopriv_get_firebase_data', 'handle_firebase_request');
page.php でのAJAX呼び出し
<script>
jQuery(document).ready(function($) {
const token = 'YOUR_TOKEN_HERE'; // 実際のトークンに置き換え
$.ajax({
url: '<?php echo admin_url('admin-ajax.php'); ?>',
type: 'POST',
data: {
action: 'get_firebase_data',
token: token
},
success: function(response) {
if (response.success) {
console.log('Session ID:', response.data.sessionId);
console.log('所属コード:', response.data.affiliationCode);
// ローカルストレージに保存
localStorage.setItem('affiliationCode', response.data.affiliationCode);
localStorage.setItem('sessionId', response.data.sessionId);
// ページに表示
$('#result').html('所属コード: ' + response.data.affiliationCode);
} else {
console.error('Error:', response.data);
}
},
error: function(xhr, status, error) {
console.error('AJAX Error:', error);
}
});
});
</script>
<div id="result"></div>
Firebase Functions側の確認ポイント
const functions = require('firebase-functions');
const cors = require('cors')({origin: true});
exports.yourFunction = functions.https.onRequest((req, res) => {
// CORSを有効化
return cors(req, res, async () => {
// POSTメソッドのみ許可
if (req.method !== 'POST') {
return res.status(405).send('Method Not Allowed');
}
try {
const { token } = req.body;
if (!token) {
return res.status(400).json({ error: 'Token is required' });
}
// トークン検証処理
// const verified = await verifyToken(token);
// レスポンスを返す
return res.status(200).json({
sessionId: 'session_123',
affiliationCode: 'AFFIL_001'
});
} catch (error) {
console.error('Error:', error);
return res.status(500).json({ error: error.message });
}
});
});
デバッグ方法
現在のコードを確認するために、以下を教えていただけますか?
- functions.php のコード - Firebase にリクエストを送っている部分
- Firebase Functions のコード - レスポンスを返している部分
- エラーメッセージの全文 - 具体的なエラー内容
また、WordPress の wp-config.php に以下を追加してデバッグログを確認してください:
define('WP_DEBUG', true);
define('WP_DEBUG_LOG', true);
define('WP_DEBUG_DISPLAY', false);
ログは wp-content/debug.log に出力されます。
念のため、動作確認のポイント
修正後、以下を確認してみてください:
1. レスポンスデータの確認
$response = wp_remote_post($firebase_url, $args);
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
// デバッグ用(確認後は削除)
error_log('Firebase response: ' . print_r($data, true));
// セッションIDと所属コードが取得できているか確認
if (isset($data['sessionId']) && isset($data['affiliationCode'])) {
// 正常に取得できた
return $data;
}
2. よくあるミス
// ❌ 間違い(「OK」と表示される原因)
$response = wp_remote_post($url, $args);
echo $response; // 配列全体が文字列化される
// ✅ 正しい
$response = wp_remote_post($url, $args);
$body = wp_remote_retrieve_body($response);
$data = json_decode($body, true);
echo $data['affiliationCode']; // 正しい値が表示される
3. ローカルストレージへの保存
JavaScriptで取得したデータをローカルストレージに保存する部分も確認してください:
// AJAXレスポンス受信後
localStorage.setItem('affiliationCode', response.data.affiliationCode);
localStorage.setItem('sessionId', response.data.sessionId);
// 各ページで使用
const affiliationCode = localStorage.getItem('affiliationCode');
console.log('所属コード:', affiliationCode);
cURL を使っていた場合は別
cURL での正しい実装方法
functions.php
<?php
function get_firebase_data_with_curl($token) {
$firebase_url = 'https://YOUR-REGION-YOUR-PROJECT.cloudfunctions.net/YOUR-FUNCTION';
// cURL初期化
$ch = curl_init();
// POSTデータを準備
$post_data = json_encode(array(
'token' => $token
));
// cURLオプション設定
curl_setopt_array($ch, array(
CURLOPT_URL => $firebase_url,
CURLOPT_RETURNTRANSFER => true, // ★重要:これがないと true/false が返る
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $post_data,
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json',
'Content-Length: ' . strlen($post_data)
),
CURLOPT_TIMEOUT => 30,
CURLOPT_SSL_VERIFYPEER => true
));
// リクエスト実行
$response = curl_exec($ch);
// エラーチェック
if (curl_errno($ch)) {
$error = curl_error($ch);
curl_close($ch);
error_log('cURL Error: ' . $error);
return array('error' => $error);
}
// HTTPステータスコード取得
$http_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
if ($http_code !== 200) {
error_log('HTTP Error: ' . $http_code . ' - Response: ' . $response);
return array('error' => 'HTTP Error: ' . $http_code);
}
// JSONデコード
$data = json_decode($response, true);
if (json_last_error() !== JSON_ERROR_NONE) {
error_log('JSON Error: ' . json_last_error_msg() . ' - Raw response: ' . $response);
return array('error' => 'Invalid JSON response');
}
return $data;
}
// AJAXハンドラー
function handle_firebase_curl_request() {
$token = isset($_POST['token']) ? sanitize_text_field($_POST['token']) : '';
if (empty($token)) {
wp_send_json_error(array('message' => 'Token is required'));
}
$result = get_firebase_data_with_curl($token);
if (isset($result['error'])) {
wp_send_json_error($result);
} else {
wp_send_json_success($result);
}
}
add_action('wp_ajax_get_firebase_data', 'handle_firebase_curl_request');
add_action('wp_ajax_nopriv_get_firebase_data', 'handle_firebase_curl_request');
重要なポイント
「OK」が表示された原因
// ❌ これだと「1」や「OK」が返る
curl_setopt($ch, CURLOPT_RETURNTRANSFER, false); // またはこの設定がない
$response = curl_exec($ch); // true が返る
echo $response; // "1" や空文字が表示される
// ✅ 正しい
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // ★これが必須
$response = curl_exec($ch); // レスポンスボディが返る
$data = json_decode($response, true);
echo $data['affiliationCode']; // 正しい値が表示される
page.php での直接呼び出し(非推奨)
もしページ内で直接呼び出している場合:
<?php
// page.php
$token = 'YOUR_TOKEN';
$firebase_data = get_firebase_data_with_curl($token);
if (!isset($firebase_data['error'])) {
$session_id = $firebase_data['sessionId'];
$affiliation_code = $firebase_data['affiliationCode'];
?>
<script>
localStorage.setItem('sessionId', '<?php echo esc_js($session_id); ?>');
localStorage.setItem('affiliationCode', '<?php echo esc_js($affiliation_code); ?>');
</script>
<p>所属コード: <?php echo esc_html($affiliation_code); ?></p>
<?php
} else {
echo '<p>エラー: ' . esc_html($firebase_data['error']) . '</p>';
}
?>
デバッグ方法
// レスポンスの内容を確認
$response = curl_exec($ch);
error_log('Raw cURL response: ' . $response);
error_log('HTTP Code: ' . curl_getinfo($ch, CURLINFO_HTTP_CODE));
// 変数の中身を確認
var_dump($response); // 開発環境のみ
CURLOPT_RETURNTRANSFER => true の設定が抜けていたのが原因だと思われます。
Firebase Functions側にも問題があった場合
「非同期になっていない時のエラー」というのは、Firebase Functions でよくある問題です。
Firebase Functions でよくあるエラーパターン
1. Promise/async を適切に返していない
// ❌ 間違い:Promiseを返していない
exports.yourFunction = functions.https.onRequest((req, res) => {
const { token } = req.body;
// 非同期処理だが await していない
verifyToken(token); // Promiseが返る
res.json({
sessionId: 'session_123',
affiliationCode: 'AFFIL_001'
});
// エラー: "Function returned undefined, expected Promise or value"
});
// ✅ 正しい:asyncを使う
exports.yourFunction = functions.https.onRequest(async (req, res) => {
try {
const { token } = req.body;
// awaitで待機
await verifyToken(token);
res.json({
sessionId: 'session_123',
affiliationCode: 'AFFIL_001'
});
} catch (error) {
res.status(500).json({ error: error.message });
}
});
2. CORS設定がない
// ❌ 間違い:CORSがない(WordPressからアクセスできない)
exports.yourFunction = functions.https.onRequest((req, res) => {
res.json({ data: 'test' });
});
// ✅ 正しい:CORSを有効化
const cors = require('cors')({origin: true});
exports.yourFunction = functions.https.onRequest((req, res) => {
return cors(req, res, async () => {
res.json({ data: 'test' });
});
});
3. レスポンスを複数回送っている
// ❌ 間違い:レスポンスを2回送っている
exports.yourFunction = functions.https.onRequest(async (req, res) => {
res.json({ status: 'processing' }); // 1回目
await someAsyncOperation();
res.json({ status: 'done' }); // 2回目 → エラー!
// "Cannot send response after function has finished"
});
// ✅ 正しい:レスポンスは1回だけ
exports.yourFunction = functions.https.onRequest(async (req, res) => {
try {
await someAsyncOperation();
res.json({ status: 'done' }); // 1回だけ
} catch (error) {
res.status(500).json({ error: error.message });
}
});
推奨される完全なコード例
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const cors = require('cors')({origin: true});
// Firebaseの初期化(まだの場合)
if (!admin.apps.length) {
admin.initializeApp();
}
exports.getSessionData = functions.https.onRequest((req, res) => {
// CORSを有効化
return cors(req, res, async () => {
// POSTメソッドのみ許可
if (req.method !== 'POST') {
return res.status(405).json({ error: 'Method Not Allowed' });
}
try {
// リクエストボディからトークンを取得
const { token } = req.body;
// トークンのバリデーション
if (!token) {
return res.status(400).json({ error: 'Token is required' });
}
// 非同期処理の例(トークン検証など)
const decodedToken = await admin.auth().verifyIdToken(token);
const uid = decodedToken.uid;
// Firestoreからデータ取得(例)
const userDoc = await admin.firestore()
.collection('users')
.doc(uid)
.get();
if (!userDoc.exists) {
return res.status(404).json({ error: 'User not found' });
}
const userData = userDoc.data();
// セッションIDの生成
const sessionId = `session_${Date.now()}_${uid}`;
// レスポンスを返す(1回だけ)
return res.status(200).json({
sessionId: sessionId,
affiliationCode: userData.affiliationCode || 'DEFAULT_CODE'
});
} catch (error) {
console.error('Error:', error);
// エラーの種類に応じて適切なステータスコードを返す
if (error.code === 'auth/id-token-expired') {
return res.status(401).json({ error: 'Token expired' });
}
return res.status(500).json({
error: 'Internal server error',
message: error.message
});
}
});
});
デバッグ方法
Firebase Functions のログを確認
# ターミナルで実行
firebase functions:log --only getSessionData
または Firebase Console で確認:
https://console.firebase.google.com/project/YOUR-PROJECT/functions/logs
よくあるエラーメッセージと対処法
| エラーメッセージ | 原因 | 解決方法 |
|---|---|---|
Function returned undefined |
Promise を返していない |
async/await を使用し、return をつける |
Response already sent |
レスポンスを複数回送信 |
return res.json() で1回だけ送信 |
CORS policy error |
CORS設定がない |
cors ミドルウェアを追加 |
auth/id-token-expired |
トークンの期限切れ | トークンの有効期限を確認 |
現在のコードを共有していただけますか?
以下の情報があると、より具体的なアドバイスができます:
- Firebase Functions のコード全体
- 実際のエラーメッセージ(Firebase Console のログから)
- 使用している Firebase SDK のバージョン