<?php
/**
 * Classe générique d'envoi de requête REST avec cURL
 * 
 *  @package openads
 */
 
class MessageSenderRest {
    
    // Variables de la classe
    private $url;
    private $username;
    private $password;
    private $curl;
    private $contentType;
    private $data;
    private $headers = array(
        'content_type' => "",
        'http_code' => "",
    );
    private $response = "";
    private $acceptedContentType = array(
        'application/xml' => 'xml',
        'text/xml' => 'xml',
        'application/json' => 'json',
        'text/json' => 'json',
        'application/html' => 'html',
        'text/html' => 'html',
        'application/pdf' => 'pdf',
        'text/pdf' => 'pdf',
        'text/plain' => 'plain',
        'image/gif' => 'gif',
        'image/jpeg' => 'jpeg',
        'image/png' => 'png',
        'application/base64' => 'base64',
    );
    
    
    /**
     * Constructeur
     */
    public function __construct($url, $username = "", $password = ""){
            
        //Initialisation des variables de la classe
        $this->url = $url;
        $this->username = $username;
        $this->password = $password;
        
        //Initialisation de la session curl
        $this->curl = curl_init();
        curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($this->curl, CURLOPT_SSL_VERIFYPEER, false);
        curl_setopt($this->curl, CURLOPT_SSL_VERIFYHOST, false);
        curl_setopt($this->curl, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($this->curl, CURLOPT_BINARYTRANSFER, true);
        
        //Tente une authentification si les options ont été fournies
        if ( $this->username !== "" && $this->password !== "" ){
            curl_setopt($this->curl, CURLOPT_PROXYAUTH, CURLAUTH_ANY);
            curl_setopt($this->curl, CURLOPT_USERPWD, $this->username . ':' . $this->password);
        }
    }
    
    /**
     * Lance l'appel au webservice
     * @param string $method
     * @param string $contentType
     * @param string $file
     * 
     * @return Retourne la réponse du webservice ou -1 en cas d'erreur
     */
    public function execute($method, $contentType, $data){
        
        //L'URL d'envoi doit être non vide
        if (strcmp($this->getUrl(), "")==0) {
            return -1;
        }
        
        //Formatage des données passées en paramètre
        $data = is_array($data)?http_build_query($data):$data;
        
        curl_setopt ($this->getCurl(), CURLOPT_HTTPHEADER, Array("Content-Type: ".$contentType));
        
        //Ajoute les certaines options à la session curl selon la méthode d'envoi 
        //souhaitée
        switch ($method) {
            case 'GET':
                curl_setopt($this->getCurl(),CURLOPT_HTTPGET,true);
                break;
            case 'PUT':
                curl_setopt($this->getCurl(),CURLOPT_PUT,true);
                //Ajout du xml dans un fichier ataché à la requête
                //Crée un fichier temporaire
                $putData = tmpfile();
                //Ecrit les données dans le fichier temporaire
                fwrite($putData, $data);
                //Place le curseur au début du fichier
                fseek($putData, 0);
                //Le fichier lu par le transfert lors du chargement
                curl_setopt($this->getCurl(), CURLOPT_INFILE, $putData);
                //Taille du fichier en octet attendue
                curl_setopt($this->getCurl(), CURLOPT_INFILESIZE, strlen($data));
                break;
            case 'POST':
                curl_setopt($this->getCurl(),CURLOPT_POST,true);
                curl_setopt($this->getCurl(),CURLOPT_POSTFIELDS,$data);
                break;
            case 'DELETE':
                curl_setopt($this->getCurl(),CURLOPT_CUSTOMREQUEST,'DELETE');
                break;
            //Si aucune méthode n'a été fournie
            default:
                return -1;
        }
        // une reponse est attendue
        curl_setopt($this->getCurl(), CURLOPT_RETURNTRANSFER, true);
        //Ajoute l'url        
        curl_setopt($this->getCurl(),CURLOPT_URL,$this->getUrl());
        $this->setResponse(curl_exec($this->getCurl()));
        
        $this->treatResponse();
        
        return $this->getResponse();
    }
    
    /**
     * Va traiter le retour de l'exécution d'une requête afin d'en extraire l'header 
     * et la réponse.
     */
    private function treatResponse(){
        
        $headers = array();
        //Si la réponse n'est pas vide
        if ( $this->getResponse() !== NULL ){
            
            //Récupération des informations du transfert curl
            $info = curl_getinfo($this->getCurl());
            
            //Si la requête ne retourne aucune information
            if ( !is_array($info) ){
                return;
            }
            
            //Récupère le type de contenu et le code HTTP de la requête réponse
            $headers['content_type'] = $info['content_type'];
            $headers['http_code'] = $info['http_code'];
            
            $this->setHeaders($headers);
            
            //Décomposition des données selon le type de retour
            $acceptedContentType = $this->getAcceptedContentType();
            $contentType = isset($acceptedContentType[$info['content_type']])?$acceptedContentType[$info['content_type']]: ''; 
            switch ($contentType) {
                case 'xml':
                    $this->setResponse((array) simplexml_load_string($this->getResponse(), 'SimpleXMLElement', LIBXML_NOCDATA));
                    break;
                case 'json':
                    $this->setResponse((array) json_decode(trim($this->getResponse())));
                    break;
                //Si la réponse n'est pas un des formats supportés
                default:
                                      
                    // Le header et le contenu du retour sont séparés par une ligne vide
                    $parts  = explode("\n\r",$this->getResponse());
                    
                    //Recompose la réponse dans le cas où elle contiendrait des 
                    //sauts de lignes
                    $this->setResponse("");
                    for ( $i = 0 ; $i < count($parts) ; $i++ ) {
                        
                        if( $i > 0 ) {
                            $this->setResponse($this->getResponse()."\n\r") ;
                        }
                        $this->setResponse($this->getResponse().$parts[$i]) ;
                    }
                    break;
                }
        }
        
        
    }
    
    /**
     * Destructeur
     */
    public function __destruct(){
        curl_close($this->curl);
    }
    
    /**
     * Ferme la connexion curl
     */
    public function close(){
        curl_close($this->curl);
    }
    
    // {{{ Accesseur
    /**
     * @return string 
     */
    public function getUrl() {
        return $this->url;
    }

    /**
     * @return object 
     */
    public function getCurl() {
        return $this->curl;
    }
    
    /**
     * @return array 
     */
    public function getHeaders() {
        return $this->headers;
    }
    
    /**
     * @return string 
     */
    public function getResponse() {
        return $this->response;
    }
    
    /**
     * @return numeric 
     */
    public function getResponseCode() {
        return $this->headers['http_code'];
    }
    
    /**
     * @return string 
     */
    public function getResponseContentType() {
        return $this->headers['content_type'];
    }
    
    /**
     * @return array
     */
    public function getAcceptedContentType() {
        return $this->acceptedContentType;
    }
    
    /**
     * @return string
     */
    public function getErrorMessage(){
        return curl_error($this->getCurl());
    }
    // }}}
    
    // {{{ Mutateur
    /**
     * Met à jour le header.
     * @param array $headers
     */
    public function setHeaders($headers) {
        $this->headers=$headers;
    }
    
    /**
     * Met à jour la réponse.
     * @param string $response
     */
    public function setResponse($response) {
        $this->response=$response;
    }
    
    /**
     * Met à jour les types de contenu acceptés.
     * @param array $acceptedContentType
     */
    public function setAcceptedContentType($acceptedContentType) {
        $this->acceptedContentType=$acceptedContentType;
    }
    // }}}
} 

?>