はじめに
Laravelで外部API(AsanaやSlackなど)と連携する機能を開発し、ローカル環境(Dockerなど)では完璧に動作していました。
しかし、いざXserverの本番環境にデプロイして動かしてみると、なぜかAPI通信の部分でエラーが発生…。
ログを確認すると Undefined constant “CURL_SSLVERSION_TLSv1_2” という謎のエラーが出ていました。
今回はその原因と、たった3行で解決できる対処法をシェアします。
対象となる環境・バージョン
この現象は、以下の環境で発生することが確認されています。
- Laravel: 6.x / 7.x / 8.x / 9.x / 10.x / 11.x
- ※Laravelが依存している「Guzzle」というライブラリを使用している環境全般
- PHP: 7.4 / 8.0 / 8.1 / 8.2 / 8.3
- サーバー: Xserver などの共用レンタルサーバー
- 特に、長期間契約していて古いサーバー環境(SV番号が古いなど)のままPHPのバージョンだけ上げた場合に発生しやすいです。
重要: 「PHPのバージョンを最新(8.x)にしているから大丈夫」ではありません。PHPのバージョンに関わらず、サーバーOS側のライブラリ(libcurl)が古いと発生します。
発生したエラー
storage/logs/laravel.log を確認すると、Guzzle(LaravelのHTTPクライアント)がクラッシュしていました。
Plaintext
[202X-XX-XX XX:XX:XX] production.ERROR: Undefined constant "CURL_SSLVERSION_TLSv1_2"
{"exception":"[object] (Error(code: 0): Undefined constant \"CURL_SSLVERSION_TLSv1_2\" at
.../vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php:104)
原因
サーバーに入っている cURL ライブラリ(libcurl)のバージョンが古かったこと が原因です。
Laravel(Guzzle)はセキュリティ強化のため、通信時に「TLS 1.2」を明示的に指定しようとします。その際に CURL_SSLVERSION_TLSv1_2 という定数を使用するのですが、Xserverの一部の環境(特に古くから使っているサーバー番号など)では、この定数が定義されていないことがあるようです。
解決策
サーバーのOSやライブラリをユーザー側でアップデートするのは難しいため、Laravel側で「定数がないなら定義してあげる」という処理(Polyfill)を追加します。
app/Providers/AppServiceProvider.php の boot メソッドに以下のコードを追記します。
修正ファイル: app/Providers/AppServiceProvider.php
PHP
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class AppServiceProvider extends ServiceProvider
{
/**
* Register any application services.
*/
public function register(): void
{
//
}
/**
* Bootstrap any application services.
*/
public function boot(): void
{
// ★ここを追加:本番環境で cURL の定数が未定義の場合のエラー回避策
if (!defined('CURL_SSLVERSION_TLSv1_2')) {
// 定数が定義されていなければ、整数の「6」として定義する
define('CURL_SSLVERSION_TLSv1_2', 6);
}
}
}
解説
CURL_SSLVERSION_TLSv1_2 という定数は、実体としては整数の 6 です。
PHP側で「もしこの定数が定義されていなかったら、6として定義するよ」とプログラム側で教えてあげることで、Guzzleはエラーを吐かずにそのまま処理を進めてくれます。
実際に裏側の通信ライブラリがTLS 1.2に対応していれば(今のサーバーならほぼ対応しています)、これで問題なく通信が通ります。
まとめ
- ローカルは動くのにXserver本番だけでGuzzleが落ちる時は
CURL_SSLVERSION_TLSv1_2を疑う。 - PHPのバージョンが新しくても、サーバーOSが古いと発生する。
AppServiceProviderで強制的にdefineしてあげれば解決する。
Xserverなどの共有レンタルサーバーでLaravelを運用している方の参考になれば幸いです!