1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

【PHP】Apacheのcurl設定につまずきまくった【Windows】

Last updated at Posted at 2023-05-19

Windowsユーザーの補助になればとの思いで綴りました。

環境

  • Windows 11
  • PHP 8.1.6
  • Apache 2.4

きっかけ

Slack APIのchat.postMessageを使ってlocalhostのApacheから送信しようとした。

function send_slack(string $text): void
{
    // SlackbotのtokenとchannelIDを取得
    $token = 'xoxb-XXXXXXXXXXXXXXXXXXXXX';
    $channel_id = 'XXXXXXXXXXX';
    // クエリ
    $query = 'channel='.$channel_id.'&text='.$text;
    // APIリクエストのヘッダーを作成
    $headers = [
        'Authorization: Bearer ' . $token
    ];

    // cURLを使用してAPIリクエストを送信
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, 'https://slack.com/api/chat.postMessage');
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
    curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
    curl_setopt($ch, CURLOPT_POST, true);
    curl_setopt($ch, CURLOPT_POSTFIELDS, $query);
    // curl_setopt($ch, CURLOPT_POSTFIELDS, "channel=$channel_id&text=$text");
    curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
    $response = curl_exec($ch);
    curl_close($ch);

    // APIレスポンスを返す
    // echo $response;
    return;
}

実行すると、以下のエラーが発生した。

Fatal error: Call to undefined function curl_init() in ...

確かにcurlの設定してなかった。やったろやないか、ということで取り掛かったのだが、ヒットした記事にWindowsのものがあまりなく、Linuxが大多数だったので小一時間悩んだ。

試したこと

コマンドプロンプトからモジュール一覧を表示

php -mをコマンドプロンプトで実行する。

C:\Users\username>php -m
[PHP Modules]
bcmath
calendar
Core
ctype
curl
date
dom
filter
hash
iconv
json
libxml
mbstring
mysqlnd
openssl
...

[Zend Modules]

curlが項目にあるが、機能していないということはモジュールの一部が正しく読み込めていないのだろう。
ということで色々試す。

phpの設定を確認する

phpinfo()でPHPの設定を出力したとき、有効化されていれば下図のようなcurlの項目が出る。下図は有効化した現在だから表示されているが、エラー発生時はこの項目が無かった。
image.png
ということは、読み込みに何らかの支障が出ているのだろう。

php.iniの確認

確認項目は次の通りである。

  • extension_dirがPHPのextディレクトリを指定している。
  • extension=curlのコメントアウトを解除している。openSSLのモジュールもついでに確認。

curl、openSSLをインストール

curlはダウンロード済み。openSSLは64bit版(軽量)をダウンロードしたのでC:\Program Files以下にインストール。詳細は省略します。

curlモジュールの依存関係を調べる

PHPに同梱されているdeplister.exeを使う。コマンドプロンプトでPHPを入れているディレクトリに飛んでから、以下のコマンドを実行する。

C:\PHP>deplister.exe ext\php_curl.dll

結果がこちら。

C:\PHP>deplister.exe ext\php_curl.dll
php8ts.dll,OK
libcrypto-1_1-x64.dll,OK
libssl-1_1-x64.dll,OK
CRYPT32.dll,OK
WLDAP32.dll,OK
Normaliz.dll,OK
libssh2.dll,OK
nghttp2.dll,OK
KERNEL32.dll,OK
WS2_32.dll,OK
VCRUNTIME140.dll,OK
api-ms-win-crt-heap-l1-1-0.dll,OK
api-ms-win-crt-stdio-l1-1-0.dll,OK
api-ms-win-crt-string-l1-1-0.dll,OK
api-ms-win-crt-runtime-l1-1-0.dll,OK
api-ms-win-crt-convert-l1-1-0.dll,OK
api-ms-win-crt-filesystem-l1-1-0.dll,OK
api-ms-win-crt-time-l1-1-0.dll,OK
api-ms-win-crt-utility-l1-1-0.dll,OK

OKでなくNOT_FOUNDなどになっていたらモジュールが無かったり、破損していたりすることがある。openSSLやVisual C++ 再頒布可能パッケージなどを整えるとこれらのファイルは揃うはず。
大体の記事がここまでで解決している(?)ようだったが、私は解決しなかった。ここから色々調べた結果、次の方法で動作するようになった。

【結論】httpd.confに追記する

ファイル末尾に以下の記述を追加した。

# cURL
LoadFile "C:\PHP\libssh2.dll"
LoadFile "C:\PHP\libcrypto-1_1-x64.dll"
LoadFile "C:\PHP\libssl-1_1-x64.dll"

これは正攻法なのだろうか…と思いつつ、追記後Apacheを再起動すると、phpinfo()にもcurlの項目が追加され、Slackにも送信ができるようになった。これにて解決!

と思いきや、もう一波あった

Fatal error: Uncaught GuzzleHttp\Exception\RequestException: cURL error 60: SSL certificate problem: unable to get local issuer certificate (see https://curl.haxx.se/libcurl/c/libcurl-errors.html) for https://oauth2.googleapis.com/token in ...

これはSlack APIではなく、Google Sheet APIを叩いたときに起こっているようだ。対処法は次の2つがあるらしい。

  1. SSL証明書の検証を無効化する
  2. 正しいルート証明書を設定する

1はセキュリティ的によろしくないだったので、2を試した。

ルート証明書を設定する

今回は提供されている証明書を利用した。自己産の証明書を生成する方法は他の方の記事を参照。以下からcacert.pemをダウンロードする。

cacert.pemを適当な場所に設置し、php.iniに証明書のパスを追記する。私はopenSSLのフォルダ内に設置したため、以下のようになる。

curl.cainfo = "C:\Program Files\OpenSSL-Win64\cacert.pem"
1
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?