Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 4.2.x will end 22 April 2024 (12 months).
  • Bug fixes for security issues in 4.2.x will end 7 October 2024 (18 months).
  • PHP version: minimum PHP 8.0.0 Note: minimum PHP version has increased since Moodle 4.1. PHP 8.1.x is supported too.
   1  <?php
   2  // This file is part of Moodle - http://moodle.org/
   3  //
   4  // Moodle is free software: you can redistribute it and/or modify
   5  // it under the terms of the GNU General Public License as published by
   6  // the Free Software Foundation, either version 3 of the License, or
   7  // (at your option) any later version.
   8  //
   9  // Moodle is distributed in the hope that it will be useful,
  10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  12  // GNU General Public License for more details.
  13  //
  14  // You should have received a copy of the GNU General Public License
  15  // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
  16  
  17  /**
  18   * This file contains the class moodle_google_curlio.
  19   *
  20   * @package core_google
  21   * @copyright 2013 Frédéric Massart
  22   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  23   */
  24  
  25  defined('MOODLE_INTERNAL') || die();
  26  
  27  require_once($CFG->libdir . '/filelib.php');
  28  
  29  /**
  30   * Class moodle_google_curlio.
  31   *
  32   * The initial purpose of this class is to add support for our
  33   * class curl in Google_IO_Curl. It mostly entirely overrides it.
  34   *
  35   * @package core_google
  36   * @copyright 2013 Frédéric Massart
  37   * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
  38  */
  39  class moodle_google_curlio extends Google_IO_Curl {
  40  
  41      /** @var array associate array of constant value and their name. */
  42      private static $constants = null;
  43  
  44      /** @var array options. */
  45      private $options = array();
  46  
  47      /**
  48       * Send the request via our curl object.
  49       *
  50       * @param curl $curl prepared curl object.
  51       * @param Google_HttpRequest $request The request.
  52       * @return string result of the request.
  53       */
  54      private function do_request($curl, $request) {
  55          $url = $request->getUrl();
  56          $method = $request->getRequestMethod();
  57          switch (strtoupper($method)) {
  58              case 'POST':
  59                  $ret = $curl->post($url, $request->getPostBody());
  60                  break;
  61              case 'GET':
  62                  $ret = $curl->get($url);
  63                  break;
  64              case 'HEAD':
  65                  $ret = $curl->head($url);
  66                  break;
  67              case 'PUT':
  68                  $ret = $curl->put($url);
  69                  break;
  70              default:
  71                  throw new coding_exception('Unknown request type: ' . $method);
  72                  break;
  73          }
  74          return $ret;
  75      }
  76  
  77      /**
  78       * Execute an API request.
  79       *
  80       * This is a copy/paste from the parent class that uses Moodle's implementation
  81       * of curl. Portions have been removed or altered.
  82       *
  83       * @param Google_Http_Request $request the http request to be executed
  84       * @return Google_Http_Request http request with the response http code, response
  85       * headers and response body filled in
  86       * @throws Google_IO_Exception on curl or IO error
  87       */
  88      public function executeRequest(Google_Http_Request $request) {
  89          $curl = new curl();
  90  
  91          if ($request->getPostBody()) {
  92              $curl->setopt(array('CURLOPT_POSTFIELDS' => $request->getPostBody()));
  93          }
  94  
  95          $requestHeaders = $request->getRequestHeaders();
  96          if ($requestHeaders && is_array($requestHeaders)) {
  97              $curlHeaders = array();
  98              foreach ($requestHeaders as $k => $v) {
  99                  $curlHeaders[] = "$k: $v";
 100              }
 101              $curl->setopt(array('CURLOPT_HTTPHEADER' => $curlHeaders));
 102          }
 103  
 104          $curl->setopt(array('CURLOPT_URL' => $request->getUrl()));
 105  
 106          $curl->setopt(array('CURLOPT_CUSTOMREQUEST' => $request->getRequestMethod()));
 107          $curl->setopt(array('CURLOPT_USERAGENT' => $request->getUserAgent()));
 108  
 109          $curl->setopt(array('CURLOPT_FOLLOWLOCATION' => false));
 110          $curl->setopt(array('CURLOPT_SSL_VERIFYPEER' => true));
 111          $curl->setopt(array('CURLOPT_RETURNTRANSFER' => true));
 112          $curl->setopt(array('CURLOPT_HEADER' => true));
 113  
 114          if ($request->canGzip()) {
 115              $curl->setopt(array('CURLOPT_ENCODING' => 'gzip,deflate'));
 116          }
 117  
 118          $curl->setopt($this->options);
 119          $respdata = $this->do_request($curl, $request);
 120  
 121          $infos = $curl->get_info();
 122          $respheadersize = $infos['header_size'];
 123          $resphttpcode = (int) $infos['http_code'];
 124          $curlerrornum = $curl->get_errno();
 125          $curlerror = $curl->error;
 126  
 127          if ($curlerrornum != CURLE_OK) {
 128              throw new Google_IO_Exception($curlerror);
 129          }
 130  
 131          list($responseHeaders, $responseBody) = $this->parseHttpResponse($respdata, $respheadersize);
 132          return array($responseBody, $responseHeaders, $resphttpcode);
 133      }
 134  
 135      /**
 136       * Set curl options.
 137       *
 138       * We overwrite this method to ensure that the data passed meets
 139       * the requirement of our curl implementation and so that the keys
 140       * are strings, and not curl constants.
 141       *
 142       * @param array $optparams Multiple options used by a cURL session.
 143       * @return void
 144       */
 145      public function setOptions($optparams) {
 146          $safeparams = array();
 147          foreach ($optparams as $name => $value) {
 148              if (!is_string($name)) {
 149                  $name = $this->get_option_name_from_constant($name);
 150              }
 151              $safeparams[$name] = $value;
 152          }
 153          $this->options = $options + $this->options;
 154      }
 155  
 156      /**
 157       * Set the maximum request time in seconds.
 158       *
 159       * Overridden to use the right option key.
 160       *
 161       * @param $timeout in seconds
 162       */
 163      public function setTimeout($timeout) {
 164          // Since this timeout is really for putting a bound on the time
 165          // we'll set them both to the same. If you need to specify a longer
 166          // CURLOPT_TIMEOUT, or a tigher CONNECTTIMEOUT, the best thing to
 167          // do is use the setOptions method for the values individually.
 168          $this->options['CURLOPT_CONNECTTIMEOUT'] = $timeout;
 169          $this->options['CURLOPT_TIMEOUT'] = $timeout;
 170      }
 171  
 172      /**
 173       * Get the maximum request time in seconds.
 174       *
 175       * Overridden to use the right option key.
 176       *
 177       * @return timeout in seconds.
 178       */
 179      public function getTimeout() {
 180         return $this->options['CURLOPT_TIMEOUT'];
 181      }
 182  
 183      /**
 184       * Return the name of an option based on the constant value.
 185       *
 186       * @param int $constant value of a CURL constant.
 187       * @return string name of the constant if found, or throws exception.
 188       * @throws coding_exception when the constant is not found.
 189       * @since Moodle 2.5
 190       */
 191      public function get_option_name_from_constant($constant) {
 192          if (is_null(self::$constants)) {
 193              $constants = get_defined_constants(true);
 194              $constants = isset($constants['curl']) ? $constants['curl'] : array();
 195              $constants = array_flip($constants);
 196              self::$constants = $constants;
 197          }
 198          if (isset(self::$constants[$constant])) {
 199              return self::$constants[$constant];
 200          }
 201          throw new coding_exception('Unknown curl constant value: ' . $constant);
 202      }
 203  
 204  }