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 7 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 */ 40abstract class CAS_Request_AbstractRequest 41implements 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} 381