Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 7
CRAP
0.00% covered (danger)
0.00%
0 / 67
Response
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 7
380
0.00% covered (danger)
0.00%
0 / 67
 __construct
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 6
 write
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 stream
0.00% covered (danger)
0.00%
0 / 1
56
0.00% covered (danger)
0.00%
0 / 22
 sendHeader
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 9
 setHeader
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 send
0.00% covered (danger)
0.00%
0 / 1
30
0.00% covered (danger)
0.00%
0 / 22
 quickResponse
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 4
<?php
/*
 * La classe Response permet de gérer la réponse envoyée au client (status, contenu, type, encodage)
 * son utilitée principale est de pouvoir d'envoyer un pseudo-flux de donnée au client et permettre ainsi de suivre le déroulement
 * d'une opération côté serveur par exemple. Son second aventage est qu'une fois la réponse envoyée et féermée, le script PHP peut continuer de s'executer
 * permettant ainsi une sensation de vitesse au niveau du client (inutile d'attendre la fin des insertions en base de donnée pour avoir la réponse par exemple)
 */
class Response{
    private $status;
    private $headers = [];
    private $config = [];
    private $response = "";
    private $Messages = array(
        //Informational 1xx
        100 => '100 Continue',
        101 => '101 Switching Protocols',
        //Successful 2xx
        200 => '200 OK',
        201 => '201 Created',
        202 => '202 Accepted',
        203 => '203 Non-Authoritative Information',
        204 => '204 No Content',
        205 => '205 Reset Content',
        206 => '206 Partial Content',
        226 => '226 IM Used',
        //Redirection 3xx
        300 => '300 Multiple Choices',
        301 => '301 Moved Permanently',
        302 => '302 Found',
        303 => '303 See Other',
        304 => '304 Not Modified',
        305 => '305 Use Proxy',
        306 => '306 (Unused)',
        307 => '307 Temporary Redirect',
        //Client Error 4xx
        400 => '400 Bad Request',
        401 => '401 Unauthorized',
        402 => '402 Payment Required',
        403 => '403 Forbidden',
        404 => '404 Not Found',
        405 => '405 Method Not Allowed',
        406 => '406 Not Acceptable',
        407 => '407 Proxy Authentication Required',
        408 => '408 Request Timeout',
        409 => '409 Conflict',
        410 => '410 Gone',
        411 => '411 Length Required',
        412 => '412 Precondition Failed',
        413 => '413 Request Entity Too Large',
        414 => '414 Request-URI Too Long',
        415 => '415 Unsupported Media Type',
        416 => '416 Requested Range Not Satisfiable',
        417 => '417 Expectation Failed',
        418 => '418 I\'m a teapot',
        422 => '422 Unprocessable Entity',
        423 => '423 Locked',
        426 => '426 Upgrade Required',
        428 => '428 Precondition Required',
        429 => '429 Too Many Requests',
        431 => '431 Request Header Fields Too Large',
        //Server Error 5xx
        500 => '500 Internal Server Error',
        501 => '501 Not Implemented',
        502 => '502 Bad Gateway',
        503 => '503 Service Unavailable',
        504 => '504 Gateway Timeout',
        505 => '505 HTTP Version Not Supported',
        506 => '506 Variant Also Negotiates',
        510 => '510 Not Extended',
        511 => '511 Network Authentication Required'
    );
    /**
     * Constructeur de la Response
     * @param int $status status HTTP de la réponse (404,200,500, etc)
     * @param bool|false $stream Si la réponse est un stream (avtive/désactive les méthodes send/stream()
     * @param string $type type HTTP des données de retour
     * @param bool|true $clearBuffer si activé, vide le buffer avant chaque envoi de donnée (a pour effet de ne pas afficher les echo/printf)
     */
    public function __construct($status = 200,$stream = false,$type = 'application/json', $clearBuffer = false)
    {
        $this->status = $status;
        array_push($this->headers,['Content-Type',$type]);
        $this->config['clearBuffer'] = $clearBuffer;
        $this->config['stream'] = $stream;
    }
    /** Ajoute du contenu a la réponse qui sera envoyé (par stream() ou par send() )
     * @param $content contenu a ajouter a la réponse
     */
    public function write($content){
        $this->response .= $content;
    }
    /** Envoie une partie de réponse au client (doit être récupéré en ajax, aucun intéret sinon), chaque bloc de donéne envoyé est séparé par
     * un délimiteur ("//Block//" par défaut).ATTENTION: stream() vide la réponse (si on write() puis stream(), la réponse qu'il restera dans l'objet sera vide)
     * @param string $content contenu a envoyer (optionnel car on peut utiliser la méthode write pour le faire)
     * @throws Exception si la réponse n'est pas un stream
     */
    public function stream($content="",$delimiter = "//Block//"){
        //vérification que la réponse est un stream
        if(!$this->config['stream']){
            throw new Exception("Stream d'une réponse synchrone");
        }
        //si les headers ne sont pas encore envoyés, on le fait
        if(!headers_sent()){
            $this->sendHeader();
        }
        //si demandé, on clear le buffer avant d'envoyer
        if($this->config['clearBuffer']){
            ob_end_clean();
            if($GLOBALS['compression']){
                ob_start("ob_gzhandler");
            }else{
                ob_start();
            }
        }
        //on envoi le contenu de response et la variable content
        if($this->response!=""){
            echo $delimiter.$this->response;
        }if($content != ""){
            echo $delimiter.$content;
        }
        ob_flush();flush();
        $this->response = '';
    }
    /**
     * Envoi les headers de la réponse (status et ceux potentiellement défnini par l'utilisateur)
     */
    public function sendHeader(){
        //envoie le status de la requete (petit trick suivant l'architecture de PHP)
        if (strpos(PHP_SAPI, 'cgi') === 0) {
            header(sprintf('Status: %s', $this->Messages[$this->status]));
        } else {
            header(sprintf('HTTP/1.1 %s', $this->Messages[$this->status]));
        }
        //les autres headers
        foreach($this->headers as $header){
            header(sprintf('%s: %s',$header[0],$header[1]));
        }
    }
    /**
     * Défini un header qui sera envoyé
     * @param $header Nom du header
     * @param $value Valeur du header
     */
    public function setHeader($header,$value){
        array_push($this->headers,[$header,$value]);
    }
    /** Envoi la réponse et ferme la communication
     * @throws Exception si la réponse est un stream
     */
    public function send(){
        //vérification que la réponse n'est pas un stream
        if($this->config['stream']){
            throw new Exception("Envoi synchrone d'une réponse stream");
        }
        //si les headers ne sont pas encore envoyés, on le fait
        if(!headers_sent()){
            $this->sendHeader();
        }
        //si demandé, on clear le buffer avant d'envoyer
        if($this->config['clearBuffer']){
            ob_end_clean();
            if($GLOBALS['compression']){
                ob_start("ob_gzhandler");
            }else{
                ob_start();
            }
        }
        //envoi de la réponse
        echo $this->response;
        //fermeture de la communication
        header('Connection: close');
        header('Content-Length: '.ob_get_length());
        ob_end_flush();
        ob_flush();
        flush();
        //permet au reste du script de s'executer même si la réponse a été envoyé et que l'utilisateur interromp le script (changement de page, etc...)
        ignore_user_abort(true);
    }
    /**
     * @param int $status status HTTP de la réponse (404,200,500, etc)
     * @param $content
     * @param string $type
     */
    public static function quickResponse($status,$content,$type = 'application/json'){
        $response = new Response($status,false,$type);
        $response->write($content);
        $response->send();
    }
}