Search moodle.org's
Developer Documentation

See Release Notes

  • Bug fixes for general core bugs in 3.10.x will end 8 November 2021 (12 months).
  • Bug fixes for security issues in 3.10.x will end 9 May 2022 (18 months).
  • PHP version: minimum PHP 7.2.0 Note: minimum PHP version has increased since Moodle 3.8. PHP 7.3.x and 7.4.x are supported too.
   1  <?php
   2  
   3  /**
   4   * Licensed to Jasig under one or more contributor license
   5   * agreements. See the NOTICE file distributed with this work for
   6   * additional information regarding copyright ownership.
   7   *
   8   * Jasig licenses this file to you under the Apache License,
   9   * Version 2.0 (the "License"); you may not use this file except in
  10   * compliance with the License. You may obtain a copy of the License at:
  11   *
  12   * http://www.apache.org/licenses/LICENSE-2.0
  13   *
  14   * Unless required by applicable law or agreed to in writing, software
  15   * distributed under the License is distributed on an "AS IS" BASIS,
  16   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17   * See the License for the specific language governing permissions and
  18   * limitations under the License.
  19   *
  20   * PHP Version 5
  21   *
  22   * @file     CAS/Request/AbstractRequest.php
  23   * @category Authentication
  24   * @package  PhpCAS
  25   * @author   Adam Franco <afranco@middlebury.edu>
  26   * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
  27   * @link     https://wiki.jasig.org/display/CASC/phpCAS
  28   */
  29  
  30  /**
  31   * Provides support for performing web-requests via curl
  32   *
  33   * @class    CAS_Request_AbstractRequest
  34   * @category Authentication
  35   * @package  PhpCAS
  36   * @author   Adam Franco <afranco@middlebury.edu>
  37   * @license  http://www.apache.org/licenses/LICENSE-2.0  Apache License 2.0
  38   * @link     https://wiki.jasig.org/display/CASC/phpCAS
  39   */
  40  abstract class CAS_Request_AbstractRequest
  41  implements CAS_Request_RequestInterface
  42  {
  43  
  44      protected $url = null;
  45      protected $cookies = array();
  46      protected $headers = array();
  47      protected $isPost = false;
  48      protected $postBody = null;
  49      protected $caCertPath = null;
  50      protected $validateCN = true;
  51      private $_sent = false;
  52      private $_responseHeaders = array();
  53      private $_responseBody = null;
  54      private $_errorMessage = '';
  55  
  56      /*********************************************************
  57       * Configure the Request
  58      *********************************************************/
  59  
  60      /**
  61       * Set the URL of the Request
  62       *
  63       * @param string $url Url to set
  64       *
  65       * @return void
  66       * @throws CAS_OutOfSequenceException If called after the Request has been sent.
  67       */
  68      public function setUrl ($url)
  69      {
  70          if ($this->_sent) {
  71              throw new CAS_OutOfSequenceException(
  72                  'Request has already been sent cannot '.__METHOD__
  73              );
  74          }
  75  
  76          $this->url = $url;
  77      }
  78  
  79      /**
  80       * Add a cookie to the request.
  81       *
  82       * @param string $name  Name of entry
  83       * @param string $value value of entry
  84       *
  85       * @return void
  86       * @throws CAS_OutOfSequenceException If called after the Request has been sent.
  87       */
  88      public function addCookie ($name, $value)
  89      {
  90          if ($this->_sent) {
  91              throw new CAS_OutOfSequenceException(
  92                  'Request has already been sent cannot '.__METHOD__
  93              );
  94          }
  95  
  96          $this->cookies[$name] = $value;
  97      }
  98  
  99      /**
 100       * Add an array of cookies to the request.
 101       * The cookie array is of the form
 102       *     array('cookie_name' => 'cookie_value', 'cookie_name2' => cookie_value2')
 103       *
 104       * @param array $cookies cookies to add
 105       *
 106       * @return void
 107       * @throws CAS_OutOfSequenceException If called after the Request has been sent.
 108       */
 109      public function addCookies (array $cookies)
 110      {
 111          if ($this->_sent) {
 112              throw new CAS_OutOfSequenceException(
 113                  'Request has already been sent cannot '.__METHOD__
 114              );
 115          }
 116  
 117          $this->cookies = array_merge($this->cookies, $cookies);
 118      }
 119  
 120      /**
 121       * Add a header string to the request.
 122       *
 123       * @param string $header Header to add
 124       *
 125       * @return void
 126       * @throws CAS_OutOfSequenceException If called after the Request has been sent.
 127       */
 128      public function addHeader ($header)
 129      {
 130          if ($this->_sent) {
 131              throw new CAS_OutOfSequenceException(
 132                  'Request has already been sent cannot '.__METHOD__
 133              );
 134          }
 135  
 136          $this->headers[] = $header;
 137      }
 138  
 139      /**
 140       * Add an array of header strings to the request.
 141       *
 142       * @param array $headers headers to add
 143       *
 144       * @return void
 145       * @throws CAS_OutOfSequenceException If called after the Request has been sent.
 146       */
 147      public function addHeaders (array $headers)
 148      {
 149          if ($this->_sent) {
 150              throw new CAS_OutOfSequenceException(
 151                  'Request has already been sent cannot '.__METHOD__
 152              );
 153          }
 154  
 155          $this->headers = array_merge($this->headers, $headers);
 156      }
 157  
 158      /**
 159       * Make the request a POST request rather than the default GET request.
 160       *
 161       * @return void
 162       * @throws CAS_OutOfSequenceException If called after the Request has been sent.
 163       */
 164      public function makePost ()
 165      {
 166          if ($this->_sent) {
 167              throw new CAS_OutOfSequenceException(
 168                  'Request has already been sent cannot '.__METHOD__
 169              );
 170          }
 171  
 172          $this->isPost = true;
 173      }
 174  
 175      /**
 176       * Add a POST body to the request
 177       *
 178       * @param string $body body to add
 179       *
 180       * @return void
 181       * @throws CAS_OutOfSequenceException If called after the Request has been sent.
 182       */
 183      public function setPostBody ($body)
 184      {
 185          if ($this->_sent) {
 186              throw new CAS_OutOfSequenceException(
 187                  'Request has already been sent cannot '.__METHOD__
 188              );
 189          }
 190          if (!$this->isPost) {
 191              throw new CAS_OutOfSequenceException(
 192                  'Cannot add a POST body to a GET request, use makePost() first.'
 193              );
 194          }
 195  
 196          $this->postBody = $body;
 197      }
 198  
 199      /**
 200       * Specify the path to an SSL CA certificate to validate the server with.
 201       *
 202       * @param string $caCertPath  path to cert
 203       * @param bool   $validate_cn valdiate CN of certificate
 204       *
 205       * @return void
 206       * @throws CAS_OutOfSequenceException If called after the Request has been sent.
 207       */
 208      public function setSslCaCert ($caCertPath,$validate_cn=true)
 209      {
 210          if ($this->_sent) {
 211              throw new CAS_OutOfSequenceException(
 212                  'Request has already been sent cannot '.__METHOD__
 213              );
 214          }
 215          $this->caCertPath = $caCertPath;
 216          $this->validateCN = $validate_cn;
 217      }
 218  
 219      /*********************************************************
 220       * 2. Send the Request
 221      *********************************************************/
 222  
 223      /**
 224       * Perform the request.
 225       *
 226       * @return bool TRUE on success, FALSE on failure.
 227       * @throws CAS_OutOfSequenceException If called multiple times.
 228       */
 229      public function send ()
 230      {
 231          if ($this->_sent) {
 232              throw new CAS_OutOfSequenceException(
 233                  'Request has already been sent cannot send again.'
 234              );
 235          }
 236          if (is_null($this->url) || !$this->url) {
 237              throw new CAS_OutOfSequenceException(
 238                  'A url must be specified via setUrl() before the request can be sent.'
 239              );
 240          }
 241          $this->_sent = true;
 242          return $this->sendRequest();
 243      }
 244  
 245      /**
 246       * Send the request and store the results.
 247       *
 248       * @return bool TRUE on success, FALSE on failure.
 249       */
 250      abstract protected function sendRequest ();
 251  
 252      /**
 253       * Store the response headers.
 254       *
 255       * @param array $headers headers to store
 256       *
 257       * @return void
 258       */
 259      protected function storeResponseHeaders (array $headers)
 260      {
 261          $this->_responseHeaders = array_merge($this->_responseHeaders, $headers);
 262      }
 263  
 264      /**
 265       * Store a single response header to our array.
 266       *
 267       * @param string $header header to store
 268       *
 269       * @return void
 270       */
 271      protected function storeResponseHeader ($header)
 272      {
 273          $this->_responseHeaders[] = $header;
 274      }
 275  
 276      /**
 277       * Store the response body.
 278       *
 279       * @param string $body body to store
 280       *
 281       * @return void
 282       */
 283      protected function storeResponseBody ($body)
 284      {
 285          $this->_responseBody = $body;
 286      }
 287  
 288      /**
 289       * Add a string to our error message.
 290       *
 291       * @param string $message message to add
 292       *
 293       * @return void
 294       */
 295      protected function storeErrorMessage ($message)
 296      {
 297          $this->_errorMessage .= $message;
 298      }
 299  
 300      /*********************************************************
 301       * 3. Access the response
 302      *********************************************************/
 303  
 304      /**
 305       * Answer the headers of the response.
 306       *
 307       * @return array An array of header strings.
 308       * @throws CAS_OutOfSequenceException If called before the Request has been sent.
 309       */
 310      public function getResponseHeaders ()
 311      {
 312          if (!$this->_sent) {
 313              throw new CAS_OutOfSequenceException(
 314                  'Request has not been sent yet. Cannot '.__METHOD__
 315              );
 316          }
 317          return $this->_responseHeaders;
 318      }
 319  
 320      /**
 321       * Answer HTTP status code of the response
 322       *
 323       * @return int
 324       * @throws CAS_OutOfSequenceException If called before the Request has been sent.
 325       * @throws CAS_Request_Exception if the response did not contain a status code
 326       */
 327      public function getResponseStatusCode ()
 328      {
 329          if (!$this->_sent) {
 330              throw new CAS_OutOfSequenceException(
 331                  'Request has not been sent yet. Cannot '.__METHOD__
 332              );
 333          }
 334  
 335          if (!preg_match(
 336              '/HTTP\/[0-9.]+\s+([0-9]+)\s*(.*)/',
 337              $this->_responseHeaders[0], $matches
 338          )
 339          ) {
 340              throw new CAS_Request_Exception(
 341                  'Bad response, no status code was found in the first line.'
 342              );
 343          }
 344  
 345          return intval($matches[1]);
 346      }
 347  
 348      /**
 349       * Answer the body of response.
 350       *
 351       * @return string
 352       * @throws CAS_OutOfSequenceException If called before the Request has been sent.
 353       */
 354      public function getResponseBody ()
 355      {
 356          if (!$this->_sent) {
 357              throw new CAS_OutOfSequenceException(
 358                  'Request has not been sent yet. Cannot '.__METHOD__
 359              );
 360          }
 361  
 362          return $this->_responseBody;
 363      }
 364  
 365      /**
 366       * Answer a message describing any errors if the request failed.
 367       *
 368       * @return string
 369       * @throws CAS_OutOfSequenceException If called before the Request has been sent.
 370       */
 371      public function getErrorMessage ()
 372      {
 373          if (!$this->_sent) {
 374              throw new CAS_OutOfSequenceException(
 375                  'Request has not been sent yet. Cannot '.__METHOD__
 376              );
 377          }
 378          return $this->_errorMessage;
 379      }
 380  }