vendor/ovh/ovh/src/Api.php line 344

Open in your IDE?
  1. <?php
  2. # Copyright (c) 2013-2017, OVH SAS.
  3. # All rights reserved.
  4. #
  5. # Redistribution and use in source and binary forms, with or without
  6. # modification, are permitted provided that the following conditions are met:
  7. #
  8. #   * Redistributions of source code must retain the above copyright
  9. #     notice, this list of conditions and the following disclaimer.
  10. #   * Redistributions in binary form must reproduce the above copyright
  11. #     notice, this list of conditions and the following disclaimer in the
  12. #     documentation and/or other materials provided with the distribution.
  13. #   * Neither the name of OVH SAS nor the
  14. #     names of its contributors may be used to endorse or promote products
  15. #     derived from this software without specific prior written permission.
  16. #
  17. # THIS SOFTWARE IS PROVIDED BY OVH SAS AND CONTRIBUTORS ``AS IS'' AND ANY
  18. # EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
  19. # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  20. # DISCLAIMED. IN NO EVENT SHALL OVH SAS AND CONTRIBUTORS BE LIABLE FOR ANY
  21. # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
  22. # (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
  23. # LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
  24. # ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25. # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  26. # SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27. /**
  28.  * This file contains code about \Ovh\Api class
  29.  */
  30. namespace Ovh;
  31. use GuzzleHttp\Client;
  32. use GuzzleHttp\Psr7\Request;
  33. use GuzzleHttp\Psr7\Response;
  34. /**
  35.  * Wrapper to manage login and exchanges with simpliest Ovh API
  36.  *
  37.  * This class manage how works connections to the simple Ovh API with
  38.  * login method and call wrapper
  39.  * Http connections use guzzle http client api and result of request are
  40.  * object from this http wrapper
  41.  *
  42.  * @package  Ovh
  43.  * @category Ovh
  44.  */
  45. class Api
  46. {
  47.     /**
  48.      * Url to communicate with Ovh API
  49.      *
  50.      * @var array
  51.      */
  52.     private $endpoints = [
  53.         'ovh-eu'        => 'https://eu.api.ovh.com/1.0',
  54.         'ovh-ca'        => 'https://ca.api.ovh.com/1.0',
  55.         'ovh-us'        => 'https://api.us.ovhcloud.com/1.0',
  56.         'kimsufi-eu'    => 'https://eu.api.kimsufi.com/1.0',
  57.         'kimsufi-ca'    => 'https://ca.api.kimsufi.com/1.0',
  58.         'soyoustart-eu' => 'https://eu.api.soyoustart.com/1.0',
  59.         'soyoustart-ca' => 'https://ca.api.soyoustart.com/1.0',
  60.         'runabove-ca'   => 'https://api.runabove.com/1.0',
  61.     ];
  62.     /**
  63.      * Contain endpoint selected to choose API
  64.      *
  65.      * @var string
  66.      */
  67.     private $endpoint null;
  68.     /**
  69.      * Contain key of the current application
  70.      *
  71.      * @var string
  72.      */
  73.     private $application_key null;
  74.     /**
  75.      * Contain secret of the current application
  76.      *
  77.      * @var string
  78.      */
  79.     private $application_secret null;
  80.     /**
  81.      * Contain consumer key of the current application
  82.      *
  83.      * @var string
  84.      */
  85.     private $consumer_key null;
  86.     /**
  87.      * Contain delta between local timestamp and api server timestamp
  88.      *
  89.      * @var string
  90.      */
  91.     private $time_delta null;
  92.     /**
  93.      * Contain http client connection
  94.      *
  95.      * @var Client
  96.      */
  97.     private $http_client null;
  98.     /**
  99.      * Construct a new wrapper instance
  100.      *
  101.      * @param string $application_key    key of your application.
  102.      *                                   For OVH APIs, you can create a application's credentials on
  103.      *                                   https://api.ovh.com/createApp/
  104.      * @param string $application_secret secret of your application.
  105.      * @param string $api_endpoint       name of api selected
  106.      * @param string $consumer_key       If you have already a consumer key, this parameter prevent to do a
  107.      *                                   new authentication
  108.      * @param Client $http_client        instance of http client
  109.      *
  110.      * @throws Exceptions\InvalidParameterException if one parameter is missing or with bad value
  111.      */
  112.     public function __construct(
  113.         $application_key,
  114.         $application_secret,
  115.         $api_endpoint,
  116.         $consumer_key null,
  117.         Client $http_client null
  118.     ) {
  119.         if (!isset($api_endpoint)) {
  120.             throw new Exceptions\InvalidParameterException("Endpoint parameter is empty");
  121.         }
  122.         if (preg_match('/^https?:\/\/..*/',$api_endpoint))
  123.         {
  124.           $this->endpoint         $api_endpoint;
  125.         }
  126.         else
  127.         {
  128.           if (!array_key_exists($api_endpoint$this->endpoints)) {
  129.               throw new Exceptions\InvalidParameterException("Unknown provided endpoint");
  130.           }
  131.           else
  132.           {
  133.             $this->endpoint       $this->endpoints[$api_endpoint];
  134.           }
  135.         }
  136.         if (!isset($http_client)) {
  137.             $http_client = new Client([
  138.                 'timeout'         => 30,
  139.                 'connect_timeout' => 5,
  140.             ]);
  141.         }
  142.         $this->application_key    $application_key;
  143.         $this->application_secret $application_secret;
  144.         $this->http_client        $http_client;
  145.         $this->consumer_key       $consumer_key;
  146.         $this->time_delta         null;
  147.     }
  148.     /**
  149.      * Calculate time delta between local machine and API's server
  150.      *
  151.      * @throws \GuzzleHttp\Exception\ClientException if http request is an error
  152.      * @return int
  153.      */
  154.     private function calculateTimeDelta()
  155.     {
  156.         if (!isset($this->time_delta)) {
  157.             $response         $this->rawCall(
  158.                 'GET',
  159.                 "/auth/time",
  160.                 null,
  161.                 false
  162.             );
  163.             $serverTimestamp  = (int)(string)$response->getBody();
  164.             $this->time_delta $serverTimestamp - (int)\time();
  165.         }
  166.         return $this->time_delta;
  167.     }
  168.     /**
  169.      * Request a consumer key from the API and the validation link to
  170.      * authorize user to validate this consumer key
  171.      *
  172.      * @param array  $accessRules list of rules your application need.
  173.      * @param string $redirection url to redirect on your website after authentication
  174.      *
  175.      * @return mixed
  176.      * @throws \GuzzleHttp\Exception\ClientException if http request is an error
  177.      */
  178.     public function requestCredentials(
  179.         array $accessRules,
  180.         $redirection null
  181.     ) {
  182.         $parameters              = new \StdClass();
  183.         $parameters->accessRules $accessRules;
  184.         $parameters->redirection $redirection;
  185.         //bypass authentication for this call
  186.         $response $this->decodeResponse(
  187.             $this->rawCall(
  188.                 'POST',
  189.                 '/auth/credential',
  190.                 $parameters,
  191.                 true
  192.             )
  193.         );
  194.         $this->consumer_key $response["consumerKey"];
  195.         return $response;
  196.     }
  197.     /**
  198.      * This is the main method of this wrapper. It will
  199.      * sign a given query and return its result.
  200.      *
  201.      * @param string               $method           HTTP method of request (GET,POST,PUT,DELETE)
  202.      * @param string               $path             relative url of API request
  203.      * @param \stdClass|array|null $content          body of the request
  204.      * @param bool                 $is_authenticated if the request use authentication
  205.      *
  206.      * @return array
  207.      * @throws \GuzzleHttp\Exception\ClientException if http request is an error
  208.      */
  209.     protected function rawCall($method$path$content null$is_authenticated true$headers null)
  210.     {
  211.         if ( $is_authenticated )
  212.         {
  213.             if (!isset($this->application_key)) {
  214.                 throw new Exceptions\InvalidParameterException("Application key parameter is empty");
  215.             }
  216.             if (!isset($this->application_secret)) {
  217.                 throw new Exceptions\InvalidParameterException("Application secret parameter is empty");
  218.             }
  219.         }
  220.         $url     $this->endpoint $path;
  221.         $request = new Request($method$url);
  222.         if (isset($content) && $method == 'GET') {
  223.             $query_string $request->getUri()->getQuery();
  224.             $query = array();
  225.             if (!empty($query_string)) {
  226.                 $queries explode('&'$query_string);
  227.                 foreach ($queries as $element) {
  228.                     $key_value_query explode('='$element2);
  229.                     $query[$key_value_query[0]] = $key_value_query[1];
  230.                 }
  231.             }
  232.             $query array_merge($query, (array)$content);
  233.             // rewrite query args to properly dump true/false parameters
  234.             foreach ($query as $key => $value) {
  235.                 if ($value === false) {
  236.                     $query[$key] = "false";
  237.                 } elseif ($value === true) {
  238.                     $query[$key] = "true";
  239.                 }
  240.             }
  241.             $query = \GuzzleHttp\Psr7\build_query($query);
  242.             $url     $request->getUri()->withQuery($query);
  243.             $request $request->withUri($url);
  244.             $body    "";
  245.         } elseif (isset($content)) {
  246.             $body json_encode($contentJSON_UNESCAPED_SLASHES);
  247.             $request->getBody()->write($body);
  248.         } else {
  249.             $body "";
  250.         }
  251.         if(!is_array($headers))
  252.         {
  253.             $headers = [];
  254.         }
  255.         $headers['Content-Type']      = 'application/json; charset=utf-8';
  256.         if ($is_authenticated) {
  257.             $headers['X-Ovh-Application'] = $this->application_key;
  258.             if (!isset($this->time_delta)) {
  259.                 $this->calculateTimeDelta();
  260.             }
  261.             $now time() + $this->time_delta;
  262.             $headers['X-Ovh-Timestamp'] = $now;
  263.             if (isset($this->consumer_key)) {
  264.                 $toSign                     $this->application_secret '+' $this->consumer_key '+' $method
  265.                     '+' $url '+' $body '+' $now;
  266.                 $signature                  '$1$' sha1($toSign);
  267.                 $headers['X-Ovh-Consumer']  = $this->consumer_key;
  268.                 $headers['X-Ovh-Signature'] = $signature;
  269.             }
  270.         }
  271.         /** @var Response $response */
  272.         return $this->http_client->send($request, ['headers' => $headers]);
  273.     }
  274.     /**
  275.      * Decode a Response object body to an Array
  276.      *
  277.      * @param  Response $response
  278.      *
  279.      * @return array
  280.      */
  281.     private function decodeResponse(Response $response)
  282.     {
  283.         return json_decode($response->getBody(), true);
  284.     }
  285.     /**
  286.      * Wrap call to Ovh APIs for GET requests
  287.      *
  288.      * @param string $path    path ask inside api
  289.      * @param array  $content content to send inside body of request
  290.      * @param array  headers  custom HTTP headers to add on the request
  291.      * @param bool   is_authenticated   if the request need to be authenticated
  292.      *
  293.      * @return array
  294.      * @throws \GuzzleHttp\Exception\ClientException if http request is an error
  295.      */
  296.     public function get($path$content null$headers null$is_authenticated true)
  297.     {
  298.         if(preg_match('/^\/[^\/]+\.json$/'$path))
  299.         {
  300.           // Schema description must be access without authentication
  301.           return $this->decodeResponse(
  302.               $this->rawCall("GET"$path$contentfalse$headers)
  303.           );
  304.         }
  305.         else
  306.         {
  307.           return $this->decodeResponse(
  308.               $this->rawCall("GET"$path$content$is_authenticated$headers)
  309.           );
  310.         }
  311.     }
  312.     /**
  313.      * Wrap call to Ovh APIs for POST requests
  314.      *
  315.      * @param string $path    path ask inside api
  316.      * @param array  $content content to send inside body of request
  317.      * @param array  headers  custom HTTP headers to add on the request
  318.      * @param bool   is_authenticated   if the request need to be authenticated
  319.      *
  320.      * @return array
  321.      * @throws \GuzzleHttp\Exception\ClientException if http request is an error
  322.      */
  323.     public function post($path$content null$headers null$is_authenticated true)
  324.     {
  325.         return $this->decodeResponse(
  326.             $this->rawCall("POST"$path$content$is_authenticated$headers)
  327.         );
  328.     }
  329.     /**
  330.      * Wrap call to Ovh APIs for PUT requests
  331.      *
  332.      * @param string $path    path ask inside api
  333.      * @param array  $content content to send inside body of request
  334.      * @param array  headers  custom HTTP headers to add on the request
  335.      * @param bool   is_authenticated   if the request need to be authenticated
  336.      *
  337.      * @return array
  338.      * @throws \GuzzleHttp\Exception\ClientException if http request is an error
  339.      */
  340.     public function put($path$content$headers null$is_authenticated true)
  341.     {
  342.         return $this->decodeResponse(
  343.             $this->rawCall("PUT"$path$content$is_authenticated$headers)
  344.         );
  345.     }
  346.     /**
  347.      * Wrap call to Ovh APIs for DELETE requests
  348.      *
  349.      * @param string $path    path ask inside api
  350.      * @param array  $content content to send inside body of request
  351.      * @param array  headers  custom HTTP headers to add on the request
  352.      * @param bool   is_authenticated   if the request need to be authenticated
  353.      *
  354.      * @return array
  355.      * @throws \GuzzleHttp\Exception\ClientException if http request is an error
  356.      */
  357.     public function delete($path$content null$headers null$is_authenticated true)
  358.     {
  359.         return $this->decodeResponse(
  360.             $this->rawCall("DELETE"$path$content$is_authenticated$headers)
  361.         );
  362.     }
  363.     /**
  364.      * Get the current consumer key
  365.      */
  366.     public function getConsumerKey()
  367.     {
  368.         return $this->consumer_key;
  369.     }
  370.     /**
  371.      * Return instance of http client
  372.      */
  373.     public function getHttpClient()
  374.     {
  375.         return $this->http_client;
  376.     }
  377. }