13.

PHP / JavaScript / Node.js で OS・実行環境を判定して処理分岐する方法

編集
この記事の要点
  • PHP: PHP_OS_FAMILY (PHP 7.2+) が最も簡単。値は Windows / Linux / Darwin / BSD / Solaris / Unknown
  • 古い PHP: PHP_OS / php_uname("s") / DIRECTORY_SEPARATOR の比較
  • Laravel: 環境名は app()->environment() または App::environment("local").envAPP_ENV
  • JavaScript (ブラウザ): navigator.userAgent / navigator.platform / navigator.userAgentData (Client Hints)
  • Node.js: process.platform (win32 / linux / darwin) + process.arch (x64 / arm64)
  • 環境変数で分岐するほうが安全(APP_ENV=production 等)。OS 判定は最終手段
  • CI 判定: GitHub Actions $GITHUB_ACTIONS、GitLab $GITLAB_CI、一般 $CI=true

OS / 環境判定が必要になるケース

  • パス区切り(Windows \ vs Unix /)の調整
  • 外部コマンド呼び出し(where vs whichcmd /c vs sh -c
  • 改行コード(CRLF / LF)の正規化
  • 開発環境とプロダクションで挙動を分ける(ログ詳細度、メール送信先など)
  • CI でだけスキップしたいテスト

PHP での環境判定

= 80100) {
    // PHP 8.1 以上の機能を使う
}

// === 環境変数で分岐(最も安全) ===
$env = getenv('APP_ENV') ?: 'production';
if ($env === 'local' || $env === 'development') {
    error_reporting(E_ALL);
    ini_set('display_errors', '1');
}

Laravel の環境判定

environment('local')) {
    // ローカルだけのデバッグ処理
}

// 複数チェック
if (app()->environment(['local', 'staging'])) {
    // 開発系全般
}

// 本番のみ
if (app()->environment('production')) {
    Mail::to($realUser)->send(new WelcomeMail());
} else {
    // 開発中はテスト用宛先へ
    Mail::to('dev@example.com')->send(new WelcomeMail());
}

// Blade 内
// @env('local')
//     
// @endenv

// @production
//     
// @endproduction

JavaScript (ブラウザ) での環境判定

// === User-Agent ベース(非推奨だが古典的) ===
const ua = navigator.userAgent;

const isIOS     = /iPad|iPhone|iPod/.test(ua);
const isAndroid = /Android/.test(ua);
const isMac     = /Macintosh|Mac OS/.test(ua);
const isWin     = /Windows/.test(ua);

// === navigator.platform(非推奨だが現役) ===
console.log(navigator.platform);
// "Win32" / "MacIntel" / "Linux x86_64" / "iPhone" / "iPad"

// === User-Agent Client Hints(Chromium 系の新 API) ===
if (navigator.userAgentData) {
  console.log(navigator.userAgentData.platform);  // "Windows" / "macOS" / "Android"
  console.log(navigator.userAgentData.mobile);    // true / false
  console.log(navigator.userAgentData.brands);
  // [{brand:"Chromium",version:"120"}, ...]
}

// === タッチデバイス判定 ===
const isTouch = 'ontouchstart' in window || navigator.maxTouchPoints > 0;

// === ダークモード判定 ===
const isDark = window.matchMedia('(prefers-color-scheme: dark)').matches;

// === 画面サイズ / ブレークポイント ===
const isMobile = window.matchMedia('(max-width: 768px)').matches;

Node.js での環境判定

// === プラットフォーム ===
console.log(process.platform);
// "win32" / "linux" / "darwin" / "freebsd" / "openbsd" / "sunos" / "aix"

console.log(process.arch);
// "x64" / "arm64" / "ia32"

// 分岐例
const isWindows = process.platform === 'win32';
const cmd = isWindows ? 'npm.cmd' : 'npm';

// === Node.js バージョン ===
console.log(process.versions.node);  // "20.10.0"
const [major] = process.versions.node.split('.').map(Number);
if (major < 18) {
  throw new Error('Node.js 18+ required');
}

// === 環境変数(最重要) ===
const env = process.env.NODE_ENV || 'development';
if (env === 'production') {
  // 本番のみ
}

// === CI 判定 ===
if (process.env.CI === 'true') {
  console.log('Running in CI');
}
if (process.env.GITHUB_ACTIONS) { /* GitHub Actions */ }
if (process.env.GITLAB_CI)      { /* GitLab CI */ }
if (process.env.CIRCLECI)       { /* CircleCI */ }

主要 CI の検知用環境変数

CI / プラットフォーム判定用環境変数
汎用CI=true
GitHub ActionsGITHUB_ACTIONS=true / GITHUB_RUN_ID
GitLab CIGITLAB_CI=true / CI_JOB_ID
CircleCICIRCLECI=true
JenkinsJENKINS_URL / BUILD_NUMBER
Travis CITRAVIS=true
Azure PipelinesTF_BUILD=True

ベストプラクティス

  • OS 判定よりも環境変数で分岐するほうが移植性が高い
  • UA Sniffing は壊れやすい → Feature Detection(その API が存在するかを直接調べる)を優先
  • PHP/Node 共に .envgit にコミットしない.env.example を雛形に
  • テスト用にモック可能な層に抽象化(Platform::isWindows() のようなラッパー関数)

FAQ

Q: PHP_OS_FAMILY と PHP_OS の違い
A: PHP_OS_FAMILYWindows / Linux / Darwin / BSD / Solaris / UnknownカテゴリPHP_OSWINNT / Linux / Darwin 等の詳細。分岐目的では PHP_OS_FAMILY が便利。

Q: navigator.userAgent は信頼できる?
A: 偽装可能で、ブラウザ更新でフォーマットが変わるため信頼度は低い。代替として Client Hints (navigator.userAgentData) と Feature Detection を組み合わせるのが現代的です。

Q: CI でだけテストをスキップしたい
A: process.env.CIgetenv("CI") でガード。PHPUnit なら @group ci-skip + --exclude-group ci-skip

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. インストールと設定
  2. クイックスタート & チュートリアル(初心者向け)
  3. クイックスタート & チュートリアル(中級者向け)
  4. ルーティング
  5. Bladeテンプレート(ビュー/レイアウト)
  6. コントローラー
  7. マイグレーションとテーブル定義
  8. データベースの設定
  9. Eloquentモデル (ORM)
  10. SQLとクエリビルダー
  11. バリデーション
  12. .envファイルの設定値へのアクセス
  13. 動作環境による分岐処理
  14. configフォルダ配下の設定値へのアクセス
  15. assetヘルパーを利用したpublicフォルダへのアクセス
  16. storageフォルダへのアクセス
  17. アプリケーション名の変更
  18. メンテナンス
  19. ログイン画面(認証システム)の作成
  20. ログインの必須化
  21. ログインユーザー情報の取得
  22. ルートの認証化
  23. 本番サーバーへのデプロイ方法
  24. 多言語化
  25. csrf_field
  26. ファイルのダウンロード
  27. CSVのアップロードおよび読み込み(maatwebsite/excel)
  28. ページタイトルの設定
  29. コマンド一覧
  30. エラー一覧
  31. SQLの実行ログ出力方法
  32. キャッシュのクリア
  33. Selectの結果の最初もしくは最後に任意の値を追加する方法
  34. ajaxでPOST通信する際の注意点
  35. ソーシャルログインの実装
  36. セッション情報の確認
  37. ログイン、ユーザー登録、パスワードリセット後のリダイレクト先の変更方法
  38. redirectやreturn viewにメッセージを付与する方法
  39. クッキー(cookie)の設定と取得
  40. クラスの再読み込み
  41. csrfの有効時間を変更する方法
  42. ViewComposerを用いてviewに共通の値を付与する方法
  43. View::shareを用いて共通の値を各ビューに渡す方法
  44. ミドルウェアを用いた処理の共通化
  45. Middleware内でAuth::check()などを使用する方法
  46. Controller以外でリダイレクトする方法
  47. セッションの値の取得/保存/更新/削除
  48. $requestの値を変更する方法
  49. 常時SSL化
  50. ページング(ページネーション)をする方法
  51. vue.jsとの連携
  52. Vue.jsと連携するSPA実行環境構築
  53. .envの値をvue.jsで参照する方法
  54. vue.jsを本番環境にリリースする方法
  55. could not find driver(Windows, MySQL編)