Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Ca Config Laravel Package

totten/ca-config

totten/ca-config provides a small PHP API for reading, modifying, and writing configuration files, with helpers for environment-specific settings. It suits CiviCRM-style PHP applications that need safe, programmatic config updates.

View on GitHub
Deep Wiki
Context7

Getting Started

Install via Composer (there are no runtime dependencies beyond PHP itself, and the package ships no certificates — it only discovers what the host already provides):

composer require totten/ca-config

The first thing to do is read the source. The whole library is essentially one class (src/CaConfig.php, namespace Civi\CaConfig) plus a handful of platform probes. Skim it end-to-end before copying any snippet, because a 1-star, zero-dependent package has no blog posts to fall back on and its API surface is intentionally tiny.

Your first use case will almost certainly be: "PHP can't find a CA bundle, so HTTPS calls fail with cURL error 60: unable to get local issuer certificate." Rather than hardcoding /etc/ssl/certs/ca-certificates.crt (wrong on macOS and Windows), ask the library to resolve it:

use Civi\CaConfig\CaConfig;

$ca = CaConfig::getDefault();

if ($ca && $ca->getCafile()) {
    $client = new \GuzzleHttp\Client([
        'verify' => $ca->getCafile(),
    ]);
}

For raw cURL, feed the same path into CURLOPT_CAINFO; for stream contexts, into ssl.cafile. Any other HTTP abstraction wants the same resolved path plumbed through.

A one-liner to prove it works on your machine before wiring anything up:

php -r 'require "vendor/autoload.php"; var_dump(\Civi\CaConfig\CaConfig::getDefault());'

If that returns null on a machine with working TLS, the heuristics didn't recognize your layout — that's your signal to go read the probe code and understand which paths it checks.

Implementation Patterns

Resolve once, inject everywhere. The lookup touches the filesystem and environment; calling CaConfig::getDefault() on every outbound request is wasteful and makes tests host-dependent. Bind it once:

// Laravel: a service provider or config binding
$this->app->singleton(CaConfig::class, fn () => CaConfig::getDefault());

Wrap it behind your own adapter. Given the maintenance risk (single maintainer, no ecosystem validation), don't let application code call CaConfig directly. A thin interface — CaBundleResolver::path(): ?string — lets you swap in composer/ca-bundle or an internal fork without touching call sites:

final class CaBundle
{
    public static function path(): ?string
    {
        return \Civi\CaConfig\CaConfig::getDefault()?->getCafile();
    }
}

Explicit override beats discovery. Corporate MITM proxies and FIPS-certified trust stores need a pinned bundle. Support an env var and short-circuit the library:

$caPath = config('services.tls.ca_bundle')
    ?? env('CA_BUNDLE')
    ?? \Civi\CaConfig\CaConfig::getDefault()?->getCafile();

Wire it into Guzzle as a shared client factory. Every Guzzle call in your app should go through one place:

function http(): \GuzzleHttp\Client
{
    $path = CaBundle::path();

    return new \GuzzleHttp\Client([
        // Never fall back to verify => false.
        'verify' => $path ?? true,
    ]);
}

Laravel Http facade. The facade resolves its own Guzzle client, so a shared factory isn't enough. Either macro the facade at boot or set the underlying client:

// In a service provider's boot()
Http::macro('withCa', function () {
    return Http::withOptions(['verify' => CaBundle::path() ?? true]);
});

Alternatively, configure guzzle defaults in config/services.php and read them from your factory.

Health-check / boot log. Resolve the CA config at boot and log the discovered path (or a warning if null). This converts "why is HTTPS broken in this container?" into a one-line grep:

Log::info('TLS CA bundle resolved', ['path' => CaBundle::path()]);

Test with a fixture. Inject the resolved path into your client factory; in tests, pass a fixture PEM bundle so CI doesn't depend on /etc/ssl/certs being populated (which it often isn't in slim php:8.x-cli images).

CiviCRM-adjacent code. This originates in the CiviCRM ecosystem; if you're working alongside CiviCRM, prefer this package over custom detection so behavior stays consistent with other CiviCRM calls.

Gotchas and Tips

  • Verify the API against the source. The public entry point is getDefault(), but instance accessors (cafile, capath, and any verification-intent accessors) should be confirmed in src/CaConfig.php. Low-traffic library — no guarantee the class has a stable, documented surface beyond the entry point.
  • Discovery is static, not live. Once you cache the path, an OS CA rotation (new corporate root, ca-certificates upgrade) won't be picked up until the process restarts. Cache the object and re-resolve periodically if you need to observe rotations; otherwise document the restart requirement.
  • Never let the fallback disable verification. The single most dangerous pattern here is 'verify' => $path ?? false. If discovery returns null, fail closed (use true and let Guzzle/PHP defaults apply, or throw with an actionable message) rather than silently downgrading to insecure.
  • Client parity. Stream contexts (ssl.cafile / ssl.capath), cURL (CURLOPT_CAINFO / CURLOPT_CAPATH), and Guzzle (verify) treat the same path differently — particularly around directories vs. files and on Windows. If you use more than one transport, test each.
  • Minimal container images. php:*-alpine, php:*-slim, and distroless bases ship without ca-certificates. The library can only discover what's on disk; if nothing is there, the real fix is apk add ca-certificates / apt-get install ca-certificates in your Dockerfile, not a library change.
  • Windows and macOS quirks. Expect the probe logic to favor different paths per OS. Validate a Windows dev machine and a macOS host — not just Linux CI — before assuming the resolution is correct everywhere.
  • INI overrides. openssl.cafile and curl.cainfo set in php.ini (or via -d on the CLI) are a supported override path but may be ignored by your library's own probing order. If you rely on them, confirm the library respects them — and don't set both to different files.
  • Read-only filesystems and permissions. Symlinked bundles under /etc/ssl/certs can be unreadable to a non-root process user in a hardened container. Test with the real runtime user, not root.
  • Don't make it critical-path without a fork plan. One maintainer, zero dependents, no security disclosure path documented. If you adopt it, pin the version, assign an internal owner, and keep the code small enough to vendor if upstream goes quiet — the class is small enough that forking is realistic.
  • Consider composer/ca-bundle first. In default Laravel, Guzzle already resolves a bundle via composer/ca-bundle, which is present in essentially every Composer project. Compare paths in shadow mode before replacing it — you may be re-implementing what's already there. Adopt this package only if its heuristics (INI probing, specific distro paths) genuinely surface a bundle that composer/ca-bundle misses on your install base.
  • Failure surface. Missing files, broken symlinks, and empty bundles all return null or an unusable path. Log which source was selected (env var, INI, discovered path, fallback) so a TLS ticket can be triaged from logs alone.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
skyraptor/chatter
edlugz/sasapay
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource