sopheos / pebble_http
Request / Response library
Requires
- php: >=8.2
- ext-filter: *
- ext-mbstring: *
- ext-session: *
- nyholm/psr7: ^1.8
- psr/http-factory: ^1.0
- psr/http-message: ^1.1 || ^2.0
Requires (Dev)
- guzzlehttp/psr7: ^3.0
- phpunit/phpunit: ^9.5
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Couche d'abstraction HTTP pour PHP 8.2+ : lecture de la requête, construction de la réponse, sessions et exceptions typées par statut HTTP.
La lib ne fournit ni routeur, ni middleware, ni conteneur. Response est un builder mutable : il n'implémente pas Psr\Http\Message\ResponseInterface, seul son corps est un StreamInterface PSR-7 (via nyholm/psr7).
Installation
composer require sopheos/pebble_http
Claude Code
Ce package fournit un skill Claude Code dans skills/pebble-http/. Il documente les patterns d'usage et les pièges de la librairie : redirect() qui réinitialise les en-têtes, parsing JSON qui exige un Content-Type exact, Session::start() à chaque requête, CORS trop permissif, préfixe de cookie ignoré, etc.
Dans un projet qui dépend de sopheos/pebble_http, copie-le une fois dans .claude/skills/ après composer install pour que Claude Code le charge automatiquement. Le nom du dossier doit correspondre au name déclaré dans SKILL.md :
cp -r vendor/sopheos/pebble_http/skills/pebble-http .claude/skills/pebble-http
Pour la maintenance de la lib elle-même, voir CLAUDE.md. Les bugs connus sont listés dans TODO.md.
Request
Pebble\Http\Request Récupération des données d'une requête HTTP.
Request::createFromServer() : staticLit$_SERVER,$_GET,$_POST,$_COOKIE,$_FILESetphp://inputune seule fois, par valeur.Request::create() : staticRequête vide, à remplir avecsetUri(),setServers(),setQueryParams(),setBodyParams(),setAttachements(),setCookies()(utile en test).
URL et données du serveur
uri() : stringChemin demandé, sans query string. Les//sont fusionnés et le/final est retiré, sauf s'il précède une query string (/a/?x=1donne/a/).baseUrl() : stringSchéma et hôte, par exemplehttps://example.com. Chaîne vide sansHTTP_HOST.currentUrl(bool $withQueryString = true) : stringURL complète.servers() : arrayParamètres serveur ($_SERVER).server(string $name) : mixedUn paramètre serveur, ounull.time() : intHorodatage de la requête en secondes.mtime() : floatHorodatage de la requête avec une précision à la microseconde.
Méthode HTTP
method() : stringMéthode HTTP (GET, POST, DELETE…), ouCLIen ligne de commande.isGet(),isPost(),isPut(),isPatch(),isDelete() : boolTeste la méthode.isClient() : boolVrai en ligne de commande.isAjax() : boolVrai siX-Requested-With: XMLHttpRequest.isSecure() : boolVrai si$_SERVER['HTTPS']est défini et différent deoff.X-Forwarded-Proton'est pas lu.
Cookies
cookies() : arrayTableau des cookies.cookie(string $name) : mixedValeur d'un cookie, ounull.
Données de la requête
queryParams() : arrayParamètres de la query string.queryParam(string $name) : mixedUn paramètre de la query string.bodyParams() : arrayDonnées du corps :$_POST, sinon JSON siContent-Typevaut exactementapplication/json, sinon le corps brut parsé comme une query string.bodyParam(string $name) : mixedUne donnée du corps.attachements() : arrayFichiers envoyés, indexés par nom de champ. Un champ multiple (docs[]) devient une liste de fichiers, un champ simple garde la forme native de$_FILES.attachement(string $name) : ?arrayLes données d'un champ fichier.
Client
userAgent() : ?stringUser agent.ip() : stringAdresse IP issue deREMOTE_ADDRuniquement,0.0.0.0si absente ou invalide.
Response
Pebble\Http\Response Construit une réponse HTTP. Toutes les méthodes set*/add* modifient l'instance et la renvoient.
Response::createFromServer() : staticReprend la version du protocole,securedes cookies selon HTTPS, et les en-têtes CORS de la requête (Origin,Access-Control-Request-*). N'appelle pascors().Response::create() : staticRéponse vierge.reset() : staticVide les en-têtes et le corps, garde la configuration.
Configuration
setStreamFactory(StreamFactoryInterface $factory) : static/getStreamFactory()Fabrique PSR-17 des corps,nyholm/psr7par défaut.setBuffer(int $buffer) : staticTaille des blocs deemitBody(), 0 pour tout envoyer d'un coup.setCookieDomain(),setCookiePath(),setCookieSecure(),setCookieHttponly(),setCookieSamesite()Réglages par défaut des cookies.setCookiePrefix(string $prefix) : staticStocké mais jamais appliqué (voirTODO.md).setCorsOrigin(),setCorsMethods(),setCorsHeaders()Valeurs utilisées parcors().
HTTP status
setProtocolVersion(string $version) : staticVersion du protocole,1.1ouHTTP/1.1.setStatusCode(int $code, ?string $reason = null) : staticStatut HTTP. Sans raison, celle des constantesResponse::HTTP_*est utilisée, ouUnknown Status(cas de 419).getProtocolVersion() : string/getStatusCode() : int
HTTP headers
addHeader(string $name, string $value, bool $replace = false) : staticAjoute un en-tête. Le nom est normalisé (x-foodevientX-Foo).removeHeader(string $name) : staticSupprime un en-tête.getHeaders() : array,getHeader(string $name) : array,hasHeader(string $name) : boolsetContentType(string $mime, string $charset = "UTF-8") : staticDéfinit le type. Une clé inconnue est utilisée telle quelle.$res->setContentType('jpg'); // raccourci $res->setContentType('image/jpeg'); // explicite
addCookie(string $name, $value, int $expire = 0, array $settings = []) : staticAjoute un cookie. La valeur est passée parurlencode().samesiten'accepte quelaxoustrict.removeCookie(string $name) : staticExpire un cookie.redirect(string $url = "/", bool $temporary = true) : staticRedirection 302 ou 301. Réinitialise en-têtes et corps, mais garde les cookies déjà ajoutés.cache(int $age = 86400) : staticActive le cache HTTP.noCache() : staticDésactive le cache HTTP.cors(?string $origin = null, ?string $methods = null, ?string $headers = null) : staticAjoute les en-têtes CORS, toujours avecAccess-Control-Allow-Credentials: true. Attention : aveccreateFromServer(), l'origine renvoyée est celle de la requête, quelle qu'elle soit (voirTODO.md).
Http body
setBody($body = "") : staticCorps :StreamInterface, ressource, scalaire,Stringableounull.setBodyFile(string $filename, string $mode = 'r') : staticCorps lu en flux depuis un fichier.getBody() : StreamInterfacesetText(string $data = '') : staticCorpstext/plain.setJson(mixed $data = null, int $flags = 0) : staticCorpsapplication/json. Lève\JsonExceptionsi l'encodage échoue.setJsonException(ResponseException $ex) : staticStatut et corps JSON tirés de l'exception.
Rendering
emitHeaders()Envoie les en-têtes. Ne fait rien, sans erreur, si une sortie a déjà eu lieu.emitBody(?int $bufferLength = null)Envoie le corps.emit(?int $bufferLength = null)Envoie en-têtes et corps.
Session
Pebble\Http\Session Couche d'abstraction pour manipuler les sessions.
__construct(?\SessionHandlerInterface $handler = null)Gestionnaire de session optionnel (memcache, base de données…).start(?string $id = null) : staticDémarre la session et fait expirer les données flash et temporaires. À appeler à chaque requête.id() : ?stringIdentifiant de session,nullavantstart().close() : staticÉcrit et ferme la session.destroy() : staticDétruit la session.reset() : staticSupprime toutes les variables de session.all() : arrayToutes les données.has(string $name) : boolIndique si une donnée existe.get(string $name, $default = null) : mixedValeur d'une donnée.set(string $name, mixed $value) : staticEnregistre une donnée.delete(string $name) : staticSupprime une donnée.
Flash data
Une donnée flash existe jusqu'à la requête suivante (à moins d'être re-marquée en flash).
setFlash(string $name, $value) : staticmarkFlash(string $name) : staticSans effet si la clé n'existe pas.unmarkFlash(string $name) : static
Temp data
Une donnée temporaire existe pendant une durée donnée en secondes. Une durée ≥ 2592000 (30 jours) est traitée comme un timestamp absolu.
setTemp($name, $value, $time = 300)markTemp(string $name, int $time = 300)unmarkTemp(string $name)
Exceptions
Utilisées pour gérer globalement les erreurs des réponses HTTP.
ResponseException
Hérite de Exception et implémente JsonSerializable. Statut 418 par défaut.
ResponseException::create(string $error = 'default') : staticResponseException::createWithStatus(int $status, string $error = 'default') : staticsetErrors(array $errors) : staticConfigure les erreurs.addError(string $key, mixed $value) : staticAjoute une erreur.setExtra(array $extra) : staticConfigure des données additionnelles.addExtra(string $key, mixed $value) : staticAjoute une donnée additionnelle.jsonSerialize()['status', 'error', 'errors', 'extra'].errorsetextravalentnullquand ils sont vides.
Liste des exceptions
Héritent de ResponseException.
UserExceptionErreur provenant de l'utilisateur, validation par exemple (statut 400).AccessExceptionInformations d'authentification non valides (statut 401).ForbiddenExceptionAccès interdit (statut 403).EmptyExceptionRessource introuvable (statut 404).NotAcceptableExceptionReprésentation demandée impossible (statut 406).ExpiredExceptionJeton ou session expiré (statut 419, non standard).LockExceptionRessource verrouillée (statut 423).SystemExceptionErreur d'exécution, une panne par exemple (statut 500).
Tests
composer install vendor/bin/phpunit
Les bugs connus sont figés par des tests annotés // BUG: qui vérifient le comportement actuel. Les tests de Session démarrent de vraies sessions PHP : phpunit.xml désactive session.use_cookies et session.cache_limiter pour que session_start() fonctionne en CLI.