AbstractRequest.php 10 KB

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