<?php
namespace Common\Vendor;
class QiniuApi
{

	public $_accessKey='xy0fkDpGwnufhiR-Ev-SJMW00giCr6wbTViQGNw1'; //ak
    public $_secretKey='n00Df3D1IFTEDEsHidnyQoxGkzE94m7tm4vqNVqh'; //sk

	private $_transport;
    private $_mac;
    private $_baseURL;
    const SDK_VERSION = '2.1.1';
    const SDK_USER_AGENT = 'pili-sdk-php';

    public $USE_HTTPS = false;
    public $API_HOST = 'pili.qiniuapi.com';
    public $API_VERSION = 'v2';

    public $RTCAPI_HOST = 'http://rtc.qiniuapi.com';
    public $RTCAPI_VERSION = 'v2';   //连麦版本号，可以设置 "v1" 和 "v2"

    protected static $_instance = null;


    const DELETE = "DELETE";
    const GET    = "GET";
    const POST   = "POST";

    private static $verifyPeer = false;
    private static $socketTimeout = null;
    private static $defaultHeaders = array();

    //stream
    private $_hub;
    private $_key;
    //transport.php
    public function __construct($mac,$accessKey, $secretKey)
    {
        $this->_mac = $mac;
        // $this->_transport = new Transport($mac);
        $this->_transport = $this->to_transport($mac);
        $cfg = $this->getInstance();
        $this->_baseURL = sprintf("%s/%s/rooms", $cfg->RTCAPI_HOST, $cfg->RTCAPI_VERSION);

        $this->_accessKey = $accessKey;
        $this->_secretKey = $secretKey;
    }
    //transport
    public function to_transport($mac)
    {
        $this->_mac = $mac;
    }

    public static function getInstance()
    {
        if (!(self::$_instance instanceof self)) {
            self::$_instance = new self();
        }
        return self::$_instance;
    }

    public function hub($hubname)
    {
        // return new Hub($this->_mac, $hubname);
        return $this->hub_conn($this->_mac,$hubname);
    }

    public function hub_conn($mac, $hubName)
    {
        $this->_hub = $hubName;
        // $this->_transport = new Transport($mac);
        $this->_transport = to_transport($mac);

        $cfg = $this->getInstance();
        $protocal = $cfg->USE_HTTPS === true ? "https" : "http";
        $this->_baseURL = $protocal . "://" . $cfg->API_HOST . "/v2/hubs/" . $this->_hub;
    }
    public function __get($property)
    {
        if (property_exists($this->getInstance(), $property)) {
            return $this->getInstance()->$property;
        } else {
            return null;
        }
    }

    public function __set($property, $value)
    {
        if (property_exists($this->getInstance(), $property)) {
            $this->getInstance()->$property = $value;
        }
        return $this->getInstance();
    }

    //transport.php 传输参数
    public function tran_send($method,$url, $body = null){
    	$headers = $this->_setHeaders($method, $url, $body);
    	$response = $this->send($method, $url, $body, $headers);
    	return $response->body;

    }

    private function _setHeaders($method, $url, $body = null)
    {
        if ($method != $this->GET) {
            $cType = 'application/json';
        } else {
            $cType = null;
        }
        $macToken = $this->MACToken($method, $url, $cType, $body);
        $ua =$this->getUserAgent($this->SDK_USER_AGENT, $this->SDK_VERSION);
        return array(
            'Content-Type'  => $cType,
            'User-Agent'    => $ua,
            'Authorization' => $macToken,
        );
    }

    public function MACToken($method, $url, $contentType, $body)
    {
        $url = parse_url($url);
        $data = '';
        if (!empty($url['path'])) {
            $data = $method . ' ' . $url['path'];
        }
        if (!empty($url['query'])) {
            $data .= '?' . $url['query'];
        }
        if (!empty($url['host'])) {
            $data .= "\nHost: " . $url['host'];
            if (isset($url['port'])) {
                $data .= ':' . $url['port'];
            }
        }
        if (!empty($contentType)) {
            $data .= "\nContent-Type: " . $contentType;
        }
        $data .= "\n\n";
        if (!empty($body)) {
            $data .= $body;
        }
        return 'Qiniu ' . $this->_accessKey . ':' .$this->sign($this->_secretKey, $data);
    }
    //utils.php获取签名
    public static function base64UrlEncode($str)
    {
        $find = array('+', '/');
        $replace = array('-', '_');
        return str_replace($find, $replace, base64_encode($str));
    }
     public static function base64UrlDecode($str)
    {
        $find = array('-', '_');
        $replace = array('+', '/');
        return base64_decode(str_replace($find, $replace, $str));
    }

    public static function digest($secret, $data)
    {
        return hash_hmac('sha1', $data, $secret, true);
    }
    public static function sign($secret, $data)
    {
        return $this->base64UrlEncode($this->digest($secret, $data));
    }


    public static function getUserAgent($sdkName, $sdkVersion)
    {
        $ua = sprintf("%s/%s", $sdkName, $sdkVersion);
        if (extension_loaded('curl')) {
            $curlVersion = curl_version();
            $ua .= ' curl/' . $curlVersion['version'];
        }
        $ua .= ' PHP/' . PHP_VERSION;
        return $ua;
    }

    /**
     * Send a cURL request
     * @param string $httpMethod HTTP method to use
     * @param string $url URL to send the request to
     * @param mixed $body request body
     * @param array $headers additional headers to send
     * @throws Exception if a cURL error occurs
     * @return HttpResponse
     */
    public static function send($httpMethod, $url, $body = null, $headers = array())
    {
        if ($headers == null) {
            $headers = array();
        }
        $annexHeaders = array();
        $finalHeaders = array_merge($headers, self::$defaultHeaders);
        foreach ($finalHeaders as $key => $val) {
            $annexHeaders[] = $this->getHeader($key, $val);
        }
        $lowerCaseFinalHeaders = array_change_key_case($finalHeaders);
        $ch = curl_init();
        if ($httpMethod != self::GET) {
            curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $httpMethod);
            if (is_array($body) || $body instanceof Traversable) {
                self::http_build_query_for_curl($body, $postBody);
                curl_setopt($ch, CURLOPT_POSTFIELDS, $postBody);
            } else {
                curl_setopt($ch, CURLOPT_POSTFIELDS, $body);
            }
        } elseif (is_array($body)) {
            if (strpos($url, '?') !== false) {
                $url .= "&";
            } else {
                $url .= "?";
            }
            self::http_build_query_for_curl($body, $postBody);
            $url .= urldecode(http_build_query($postBody));
        }
        curl_setopt($ch, CURLOPT_URL, self::encodeUrl($url));
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
        curl_setopt($ch, CURLOPT_MAXREDIRS, 10);
        curl_setopt($ch, CURLOPT_HTTPHEADER, $annexHeaders);
        curl_setopt($ch, CURLOPT_HEADER, true);
        curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, self::$verifyPeer);
        curl_setopt($ch, CURLOPT_ENCODING, ""); // If an empty string, "", is set, a header containing all supported encoding types is sent.
        if (self::$socketTimeout != null) {
            curl_setopt($ch, CURLOPT_TIMEOUT, self::$socketTimeout);
        }
        $response = curl_exec($ch);
        $error    = curl_error($ch);
        if ($error) {
            throw new \Exception($error);
        }
        // Split the full response in its headers and body
        $curl_info   = curl_getinfo($ch);
        $header_size = $curl_info["header_size"];
        $header      = substr($response, 0, $header_size);
        $body        = substr($response, $header_size);
        $httpCode    = $curl_info["http_code"];
        if ($httpCode >= 400) {
            throw new \Exception($body);
        }
        return new HttpResponse($httpCode, $body, $header);
    }
    /**
     * Ensure that a URL is encoded and safe to use with cURL
     * @param  string $url URL to encode
     * @return string
     */
    private static function encodeUrl($url)
    {
        $url_parsed = parse_url($url);
        $scheme = $url_parsed['scheme'] . '://';
        $host   = $url_parsed['host'];
        $port   = (isset($url_parsed['port']) ? $url_parsed['port'] : null);
        $path   = (isset($url_parsed['path']) ? $url_parsed['path'] : null);
        $query  = (isset($url_parsed['query']) ? $url_parsed['query'] : null);
        if ($query != null) {
            $query = '?' . http_build_query(self::getArrayFromQuerystring($url_parsed['query']));
        }
        if ($port && $port[0] != ":") {
            $port = ":" . $port;
        }
        $result = $scheme . $host . $port . $path . $query;
        return $result;
    }

    private static function getHeader($key, $val)
    {
        $key = trim($key);
        return $key . ": " . $val;
    }

    private static function getArrayFromQuerystring($querystring)
    {
        $pairs = explode("&", $querystring);
        $vars  = array();
        foreach ($pairs as $pair) {
            $nv          = explode("=", $pair, 2);
            $name        = $nv[0];
            $value       = $nv[1];
            $vars[$name] = $value;
        }
        return $vars;
    }
    /**
     * Clear all the default headers
     */
    public static function clearDefaultHeaders()
    {
        self::$defaultHeaders = array();
    }
    /**
     * Verify SSL peer
     * @param bool $enabled enable SSL verification, by default is false
     */
    public static function verifyPeer($enabled)
    {
        self::$verifyPeer = $enabled;
    }

    /**
     * Set a timeout
     * @param integer $seconds timeout value in seconds
     */
    public static function timeout($seconds)
    {
        self::$socketTimeout = $seconds;
    }

    /**
     * Set a new default header to send on every request
     * @param string $name header name
     * @param string $value header value
     */
    public static function defaultHeader($name, $value)
    {
        self::$defaultHeaders[$name] = $value;
    }

    /**
     * Retrieve the cURL response headers from the
     * header string and convert it into an array
     * @param  string $headers header string from cURL response
     * @return array
     */
    private function get_headers_from_curl_response($headers)
    {
        $headers = explode("\r\n", $headers);
        array_shift($headers);
        foreach ($headers as $line) {
            if (strstr($line, ': ')) {
                list($key, $value) = explode(': ', $line);
                $result[$key] = $value;
            }
        }
        return $result;
    }

    //hub
    //创建一个流对象.
    /*
     * PARAM
     * @streamKey: 流名.
     * RETURN
     * 返回一个流对象.
     */
    public function create($streamKey)
    {
        $url = $this->_baseURL . "/streams";
        $params['key'] = $streamKey;
        $body = json_encode($params);
        try {
            $this->tran_send(self::POST, $url, $body);
        } catch (\Exception $e) {
            return $e;
        }
        return $this->stream($this->_transport, $this->_hub, $streamKey);

        // return new Stream($this->_transport, $this->_hub, $streamKey);
    }

    //引用stream.php 
    public function stream($transport, $hub, $key){

    	$this->_transport = $transport;
        $this->_hub = $hub;
        $this->_key = $key;

        $cfg = $this->getInstance();
        $protocal = $cfg->USE_HTTPS === true ? "https" : "http";
        $this->_baseURL = sprintf("%s://%s/%s/hubs/%s/streams/%s", $protocal, $cfg->API_HOST, $cfg->API_VERSION, $this->_hub, $this->base64UrlEncode($this->_key));

    }
     //初始化一个流对象
    /*
     * PARAM
     * @streamKey: 流名.
     * RETURN
     * 返回一个流对象.
     */
    public function stream($streamKey)
    {
        return $this->stream($this->_transport, $this->_hub, $streamKey);
    }

    private function _list($live, $prefix, $limit, $marker)
    {
        $url = sprintf("%s/streams?liveonly=%s&prefix=%s&limit=%d&marker=%s", $this->_baseURL, $live, $prefix, $limit, $marker);
        try {
            $ret = $this->tran_send(self::GET, $url);
        } catch (\Exception $e) {
            return $e;
        }
        $keys = array();
        foreach ($ret["items"] as $item) {
            array_push($keys, $item["key"]);
        }
        $marker = $ret["marker"];
        $ret = array();
        $ret["keys"] = $keys;
        $ret["omarker"] = $marker;
        return $ret;
    }
    //根据 prefix 遍历 Hub 的正在直播的流列表.
    /*
     * PARAM
     * @prefix: 流名的前缀.
     * @limit: 限定了一次最多可以返回的流个数, 实际返回的流个数可能小于这个 limit 值.
     * @marker: 是上一次遍历得到的流标.
     * RETURN
     * @keys: 流名的数组.
     * @omarker: 记录了此次遍历到的游标, 在下次请求时应该带上, 如果 omarker 为 "" 表示已经遍历完所有流.
     */
    public function listLiveStreams($prefix, $limit, $marker)
    {
        return $this->_list("true", $prefix, $limit, $marker);
    }

    //根据 prefix 遍历 Hub 的流列表.
    /*
     * PARAM
     * @prefix: 流名的前缀.
     * @limit: 限定了一次最多可以返回的流个数, 实际返回的流个数可能小于这个 limit 值.
     * @marker: 是上一次遍历得到的流标.
     * RETURN
     * @keys: 流名的数组.
     * @omarker: 记录了此次遍历到的游标, 在下次请求时应该带上, 如果 omarker 为 "" 表示已经遍历完所有流.
     */
    public function listStreams($prefix, $limit, $marker)
    {
        return $this->_list("false", $prefix, $limit, $marker);
    }
    //批量查询流直播信息.
    /*
     * PARAM
     * @streamKeys: 流名数组, 最大长度为100.
     * RETURN
     * @items: 数组. 每个item包含一个流的直播信息.
     *   @key: 流名.
     *   @startAt: 直播开始的 Unix 时间戳, 0 表示当前没在直播.
     *   @clientIP: 直播的客户端 IP.
     *   @bps: 直播的码率.
     *   @fps: 直播的帧率.
     */
    public function batchLiveStatus($streamKeys)
    {
        $url = $this->_baseURL . "/livestreams";
        $params['items'] = $streamKeys;
        $body = json_encode($params);
        return $this->tran_send(self::POST, $url, $body);
    }
    //----------------url
	//生成 RTMP 推流地址.
	//expireAfterSeconds 表示 URL 在多久之后失效.
	function RTMPPublishURL($domain, $hub, $streamKey, $expireAfterSeconds, $accessKey, $secretKey)
	{
	    $expire = time() + $expireAfterSeconds;
	    $path = sprintf("/%s/%s?e=%d", $hub, $streamKey, $expire);
	    $token = $accessKey . ":" . $this->sign($secretKey, $path);
	    return sprintf("rtmp://%s%s&token=%s", $domain, $path, $token);
	}

	//生成 RTMP 直播地址.
	function RTMPPlayURL($domain, $hub, $streamKey)
	{
	    return sprintf("rtmp://%s/%s/%s", $domain, $hub, $streamKey);
	}

	//生成 HLS 直播地址.
	function HLSPlayURL($domain, $hub, $streamKey)
	{
	    return sprintf("http://%s/%s/%s.m3u8", $domain, $hub, $streamKey);
	}

	//生成 HDL 直播地址.
	function HDLPlayURL($domain, $hub, $streamKey)
	{
	    return sprintf("http://%s/%s/%s.flv", $domain, $hub, $streamKey);
	}

	//生成直播封面地址.
	function SnapshotPlayURL($domain, $hub, $streamKey)
	{
	    return sprintf("http://%s/%s/%s.jpg", $domain, $hub, $streamKey);
	}
	//end
	//stream.php
	//获得流信息.
    /*
     * RETURN
     * @hub: Hub名.
     * @key: 流名.
     * @disableTill: 禁用结束的时间, 0 表示不禁用, -1 表示永久禁用.
     * @converts: 实时转码规格.
    */
    public function info()
    {
        $resp=$this->tran_send(self::GET, $this->_baseURL);
        $ret = array();
        $ret["hub"] = $this->_hub;
        $ret["key"] = $this->_key;
        $ret["disabledTill"] = $resp["disabledTill"];
        $ret["converts"] = $resp["converts"];
        return $ret;
    }
    //在一定期限内禁止一个流.
    /*
     * PARAM
     * @till: Unix 时间戳, 在这之前流均不可用.
     */
    public function disable($till = null)
    {
        $url = $this->_baseURL . "/disabled";
        if (empty($till)) {
            $params['disabledTill'] = -1;
        } else {
            $params['disabledTill'] = $till;
        }
        $body = json_encode($params);
        return $this->tran_send(self::POST, $url, $body);
    }
    //启用一个流.
    public function enable()
    {
        $url = $this->_baseURL . "/disabled";
        $params['disabledTill'] = 0;
        $body = json_encode($params);
        return $this->tran_send(self::POST, $url, $body);
    }

    //查询直播状态.
    /*
     * RETURN
     * @startAt: 直播开始的 Unix 时间戳, 0 表示当前没在直播.
     * @clientIP: 直播的客户端 IP.
     * @bps: 直播的码率.
     * @fps: 直播的帧率.
     */
    public function liveStatus()
    {
        $url = $this->_baseURL . "/live";
        return $this->tran_send(self::GET, $url);
    }
    //查询直播历史.
    /*
     * PARAM
     * @start: Unix 时间戳, 限定了查询的时间范围, 0 值表示不限定, 系统会返回所有时间的直播历史.
     * @end: Unix 时间戳, 限定了查询的时间范围, 0 值表示不限定, 系统会返回所有时间的直播历史.
     * RETURN
     * @items: 数组. 每个item包含一次推流的开始及结束时间.
     *   @start: Unix 时间戳, 直播开始时间.
     *   @end: Unix 时间戳, 直播结束时间.
     */
    public function historyActivity($start = null, $end = null)
    {
        $url = $this->_baseURL . "/historyrecord";
        $flag = "?";
        if (!empty($start)) {
            $url = $url . $flag . "start=" . $start;
            $flag = "&";
        }
        if (!empty($end)) {
            $url = $url . $flag . "end=" . $end;
        }
        return $this->tran_send(self::GET, $url);
    }
    //保存直播回放.
    /*
     * PARAM
     * @start: Unix 时间戳, 起始时间, 0 值表示不指定, 则不限制起始时间.
     * @end: Unix 时间戳, 结束时间, 0 值表示当前时间.
     * RETURN
     * @fname: 保存到bucket里的文件名, 由系统生成.
     */
    public function save($start = null, $end = null)
    {
        $url = $this->_baseURL . "/saveas";
        if (!empty($start)) {
            $params['start'] = $start;
        }
        if (!empty($end)) {
            $params['end'] = $end;
        }
        $body = json_encode($params);
        return $this->tran_send(self::POST, $url, $body);
    }

     //灵活度更高的保存直播回放.
    /*
     * PARAM
     * @fname: 保存的文件名, 不指定会随机生成.
     * @start: Unix 时间戳, 起始时间, 0 值表示不指定, 则不限制起始时间.
     * @end: Unix 时间戳, 结束时间, 0 值表示当前时间.
     * @format: 保存的文件格式, 默认为m3u8.
     * @pipeline: dora 的私有队列, 不指定则用默认队列.
     * @notify: 保存成功后的回调地址.
     * @expireDays: 对应ts文件的过期时间.
     *   -1 表示不修改ts文件的expire属性.
     *   0  表示修改ts文件生命周期为永久保存.
     *   >0 表示修改ts文件的的生命周期为ExpireDays.
     * RETURN
     * @fname: 保存到bucket里的文件名.
     * @persistentID: 异步模式时，持久化异步处理任务ID，通常用不到该字段.
     */
    public function saveas($options = null)
    {
        $url = $this->_baseURL . "/saveas";
        if (!empty($options)) {
            $body = json_encode($options);
        } else {
            $body = null;
        }
        return $this->tran_send(self::POST, $url, $body);
    }
    //对流进行截图并保存.
    /*
     * PARAM
     * @fname: 保存的文件名, 不指定会随机生成.
     * @time: Unix 时间戳, 保存的时间点, 默认为当前时间.
     * @format: 保存的文件格式, 默认为jpg.
     * RETURN
     * @fname: 保存到bucket里的文件名.
     */
    public function snapshot($options = null)
    {
        $url = $this->_baseURL . "/snapshot";
        if (!empty($options)) {
            $body = json_encode($options);
        } else {
            $body = null;
        }
        return $this->tran_send(self::POST, $url, $body);
    }

    //更改流的实时转码规格
    /*
     * PARAM
     * @profiles: 实时转码规格. array("480p", "720p")
     */
    public function updateConverts($profiles)
    {
        $url = $this->_baseURL . "/converts";
        $params['converts'] = $profiles;
        $body = json_encode($params);
        return $this->tran_send(self::POST, $url, $body);
    }
	//end

}





?>