Overview

Namespaces

  • None
  • PHP

Classes

  • RESTian
  • RESTian_Application_Json_Parser
  • RESTian_Application_Serialized_Php_Parser
  • RESTian_Application_Xml_Parser
  • RESTian_Auth_Provider_Base
  • RESTian_Base
  • RESTian_Basic_Http_Auth_Provider
  • RESTian_Client
  • RESTian_Http_Agent_Base
  • RESTian_Not_Applicable_Provider
  • RESTian_Parser_Base
  • RESTian_Php_Curl_Http_Agent
  • RESTian_Request
  • RESTian_Response
  • RESTian_Service
  • RESTian_Settings
  • RESTian_Text_Csv_Parser
  • RESTian_Text_Html_Parser
  • RESTian_Text_Plain_Parser
  • RESTian_Var
  • RESTian_WordPress_Http_Agent
  • Overview
  • Namespace
  • Class
  • Tree
  • Deprecated
  • Todo
  • Download
  1: <?php
  2: 
  3: /**
  4:  * A RESTian_Request represents a specific HTTP request
  5:  */
  6: class RESTian_Request {
  7:   /**
  8:    * @var bool|array
  9:    */
 10:   protected $_credentials = false;
 11:   /**
 12:    * @var bool|array
 13:    */
 14:   protected $_grant = false;
 15:   /**
 16:    * @var array
 17:    */
 18:   protected $_headers = array();
 19:   /**
 20:    * @var RESTian_Service Optional to override the one set in the API, if needed.
 21:    */
 22:   protected $_auth_service = false;
 23:   /**
 24:    * @var RESTian_Client
 25:    */
 26:   var $client;
 27:   /**
 28:    * @var RESTian_Service
 29:    */
 30:   var $service;
 31:   /**
 32:    * @var string
 33:    */
 34:   var $http_method = 'GET';
 35:   /**
 36:    * @var bool Specifies that SSL should not be verified by default.
 37:    * When true it is often too problematic for WordPress plugins.
 38:    */
 39:   var $sslverify = false;
 40:   /**
 41:    * @var RESTian_Response
 42:    */
 43:   var $response;
 44:   /**
 45:    * @var array
 46:    */
 47:   var $vars;
 48:   /**
 49:    * @var string
 50:    */
 51:   var $body;
 52: 
 53:   /**
 54:    * @TODO These should be moved to RESPONSE, not be in REQUEST.
 55:    */
 56:   var $omit_body = false;
 57:   var $omit_result = false;
 58: 
 59:   /**
 60:    * @param array $vars
 61:    * @param array $args
 62:    */
 63:   function __construct( $vars = array(), $args = array() ) {
 64: 
 65:     if ( is_null( $vars ) )
 66:       $vars = array();
 67: 
 68:     if ( is_null( $args ) )
 69:       $args = array();
 70:     else if ( is_string( $args ) )
 71:       $args = RESTian::parse_args( $args );
 72: 
 73:     /**
 74:      * Copy properties in from $args, if they exist.
 75:      */
 76:     foreach( $args as $property => $value )
 77:       if ( property_exists(  $this, $property ) )
 78:         $this->$property = $value;
 79: 
 80:     /**
 81:      * Do these late $args cannot override them.
 82:      */
 83:     if ( isset( $this->service->client ) ) {
 84:       $this->client = $this->service->client;
 85:     }
 86: 
 87:     if ( isset( $args['credentials'] ) ) {
 88:       $this->set_credentials( $args['credentials'] );
 89:     }
 90: 
 91:     if ( isset( $args['grant'] ) ) {
 92:       $this->set_grant( $args['grant'] );
 93:     }
 94: 
 95:     if ( isset( $args['headers'] ) ) {
 96:       $this->add_headers( $args['headers'] );
 97:     }
 98: 
 99:     if ( is_array( $vars ) ) {
100:       $this->vars = $vars;
101:     } else {
102:       $this->body = $vars;
103:     }
104: 
105:   }
106: 
107:   /**
108:    * Check $this->auth to determine if it contains credentials.
109:    *
110:    * Does NOT verify if credentials are valid, only that it has them.
111:    *
112:    * This class will be extended when we have a proper use-case for extension.
113:    *
114:    * @return bool
115:    */
116:   function has_credentials() {
117:     $auth_provider = $this->client->get_auth_provider();
118:     return $auth_provider->is_credentials( $this->_credentials );
119:   }
120: 
121:   /**
122:    * @return bool|array
123:    */
124:   function get_credentials() {
125:     return $this->_credentials;
126:   }
127: 
128:   /**
129:    * @param $credentials
130:    *
131:    * @return mixed
132:    */
133:   function set_credentials( $credentials ) {
134:     $this->_credentials = $credentials;
135:   }
136: 
137:   /**
138:    * @return bool|array
139:    */
140:   function get_grant() {
141:     return $this->_grant;
142:   }
143: 
144:   /**
145:    * @param $grant
146:    *
147:    * @return mixed
148:    */
149:   function set_grant( $grant ) {
150:     $this->_grant = $grant;
151:   }
152: 
153:   /**
154:    * @return bool|RESTian_Service
155:    */
156:   function get_auth_service() {
157:     $this->client->initialize_client();
158:     if ( ! $this->_auth_service ) {
159:       $this->_auth_service = $this->client->get_auth_service();
160:     }
161:     return $this->_auth_service;
162:   }
163:   /**
164:    * @param $name
165:    * @param $value
166:    */
167:   function add_header( $name, $value ) {
168:     $this->_headers[$name] = $value;
169:   }
170: 
171:   /**
172:    * @param array $headers
173:    */
174:   function add_headers( $headers = array() ) {
175:     $this->_headers = array_merge( $this->_headers, $headers );
176:   }
177: 
178:   /**
179:    * @return array
180:    */
181:   function get_headers() {
182:     return $this->_headers;
183:   }
184: 
185:   /**
186:    *
187:    */
188:   function clear_headers() {
189:     $this->_headers = array();
190:   }
191: 
192:   /**
193:    * @return bool|string
194:    */
195:   function get_body() {
196:     $body = false;
197:     if ( preg_match( '#^(POST|PUT)$#i', $this->http_method ) ) {
198:       if ( $this->body ) {
199:         $body = $this->body;
200:       } else if ( $settings = $this->service->get_request_settings() ) {
201:         if ( RESTian::expand_content_type( 'form' ) == $settings->content_type ) {
202:           $body = http_build_query( $this->vars );
203:         } else if ( count( $this->vars ) && RESTian::expand_content_type( 'json' ) == $settings->content_type ) {
204:           $body = json_encode( (object)$this->vars );
205:         }
206:       } else if ( count( $this->vars ) ) {
207:         $body = http_build_query( $this->vars );
208:         $this->vars = null;
209:       }
210:     }
211:     return $body;
212:   }
213: 
214:   /**
215:    * Returns HTTP headers as expected by CURL.
216:    *
217:    * Returns numeric indexed array where value contains header name and header value as "{$name}: {$value}"
218:    *
219:    * @return array
220:    */
221:   function get_curl_headers() {
222:     $headers = array();
223:     foreach( $this->_headers as $name => $value )
224:       $headers[] = "{$name}: {$value}";
225:     return $headers;
226:   }
227: 
228:   /**
229:    * @return bool|string
230:    * @throws Exception
231:    */
232:   function get_url() {
233:     $service_url = $this->client->get_service_url( $this->service );
234:     if ( count( $this->vars ) ) {
235:       $query_vars = $this->vars;
236:       foreach( $query_vars as $name => $value ) {
237:         /**
238:          * @var array $matches Get all URL path var matches into an array
239:          */
240:         preg_match_all( '#([^{]+)\{([^}]+)\}#', $this->service->path, $matches );
241:         $path_vars = array_flip( $matches[2] );
242:         if ( isset( $path_vars[$name] ) ) {
243:           $var = $this->client->get_var( $name );
244:           $value = $var->apply_transforms( $value );
245:           $service_url = str_replace( "{{$name}}", $value, $service_url );
246:           unset( $query_vars[$name] );
247:         }
248:       }
249:       $service_url .= '?' . http_build_query( $query_vars );
250:     }
251:     return $service_url;
252:   }
253: 
254:   /**
255:    * @param $vars
256:    * @param $template
257:    *
258:    * @return bool|string
259:    */
260:   private function _to_application_form_url_encoded( $vars, $template = '' ) {
261:       $query_vars = $this->vars;
262:       foreach( $query_vars as $name => $value ) {
263:         /**
264:          * @var array $matches Get all URL path var matches into an array
265:          */
266:         preg_match_all( '#([^{]+)\{([^}]+)\}#', $this->service->path, $matches );
267:         $path_vars = array_flip( $matches[2] );
268:         if ( isset( $path_vars[$name] ) ) {
269:           $var = $this->client->get_var( $name );
270:           $value = $var->apply_transforms( $value );
271:           $template = str_replace( "{{$name}}", $value, $template );
272:           unset( $query_vars[$name] );
273:         }
274:       }
275:     $result = http_build_query( $query_vars );
276:     return $result;
277:   }
278:   /**
279:    * Returns true if RESTian can safely assume that we have authenticated in past with existing credentials.
280:    *
281:    * This does NOT mean we ARE authenticated but that we should ASSUME we are and try doing calls without
282:    * first authenticating. This functionality is defined because the client (often a WordPress plugin) may
283:    * have captured grant info from a prior page load where this class did authenticate, but this class is not
284:    * in control of maintaining that grant info so we can only assume it is correct if the client of this code
285:    * tells us it is by giving us grant info that the auth provider validates. Another use-case where our assumption
286:    * will fail is if the access_key expires or has since been revoked.
287:    *
288:    * @return bool
289:    */
290:   function has_grant() {
291:     return $this->client->get_auth_provider()->is_grant( $this->_grant );
292:   }
293:   /**
294:    * Call the API.
295:    *
296:    * On success (HTTP status == 200) $this->error_code and $this->error_msg will be false.
297:    * On failure (HTTP status != 200) $this->error_code and $this->error_msg will contain error information.
298:    *
299:    * On success or failure,  $this->response will contain the response captured by HTTP agent
300:    * except when username and password are not passed as part of auth.
301:    *
302:    * @return object|RESTian_Response
303:    */
304:   function make_request() {
305:     $response = new RESTian_Response( array( 'request' => $this ) );
306:     $api = $this->client;
307:     /**
308:      * Assign request & response to API so they are accessible inside the auth_provider
309:      */
310:     $api->request = $this;
311:     $api->response = $response;
312:     $auth_provider = $api->get_auth_provider();
313:     if ( $this->needs_authentication() && ! $this->has_authentication() ) {
314:       $response->set_error( 'NO_AUTH', $this->service );
315:     } else {
316:       $http_agent = RESTian::get_new_http_agent( $this->client->http_agent );
317:       $this->assign_settings();
318:       $response = $http_agent->make_request( $this, $response );
319:       if ( $response->is_http_error() ) {
320:         /**
321:          * See if we can provide more than one error type here.
322:          */
323:         $msg = 'There was a problem reaching %s when calling the %s. Please try again later or contact the site\'s administrator.';
324:         $response->set_error( 'API_FAIL', sprintf( $msg, $this->client->api_name, $this->service->service_name ) );
325:       } else {
326:         if ( 'authenticate' == $response->request->service->service_name ) {
327:           $handled = $auth_provider->authenticated( $response );
328:         } else {
329:           $handled = $auth_provider->handle_response( $response );
330:         }
331:         if ( ! $handled ) {
332:           // @todo Add more HTTP status code responses as we better understand the use-cases.
333:           switch ( $response->status_code ) {
334:             case '200':
335:               /**
336:                * @var RESTian_Parser_Base $parser
337:                */
338:               $parser = RESTian::get_new_parser( $this->service->content_type, $this, $response );
339:               if ( $parser instanceof RESTian_Parser_Base )
340:                 $response->data = $parser->parse( $response->body );
341:               break;
342:             case '401':
343:               $response->set_error( 'BAD_AUTH', $this->service );
344:               break;
345:             default:
346:               /**
347:                * See if we can provide more than one error type here.
348:                */
349:               $response->set_error( 'UNKNOWN', 'Unexpected API response code: ' . $response->status_code );
350:               break;
351:           }
352:         }
353:         if ( $this->omit_body )
354:           $response->body = null;
355:         if ( $this->omit_result )
356:           $response->result = null;
357:       }
358:     }
359:     return $response;
360:   }
361: 
362:   /**
363:    * @return bool
364:    */
365:   function needs_authentication() {
366:     return $this->service != $this->get_auth_service() && $this->service->needs_authentication;
367:   }
368: 
369:   /**
370:    * @return bool
371:    */
372:   function has_authentication() {
373:     $auth_provider = $this->client->get_auth_provider();
374:     return $auth_provider ? $auth_provider->is_grant( $this->get_grant() ) : false;
375:   }
376: 
377:   /**
378:    * @return bool|RESTian_Settings
379:    */
380:   function get_settings() {
381:     return $this->service->get_request_settings();
382:   }
383:   /**
384:     * @return bool
385:     */
386:   function get_content_type() {
387:     $content_type = false;
388:     if ( $settings = $this->get_settings() ) {
389:       if ( $settings->content_type )
390:         $content_type = $settings->content_type;
391:       if ( $content_type && $settings->charset )
392:         $content_type .= "; charset={$settings->charset}";
393:     }
394:     return $content_type;
395:   }
396: 
397:   function assign_settings() {
398:     if ( $settings = $this->service->get_request_settings() ) {
399: 
400:       if ( $settings->http_method )
401:         $this->http_method = $settings->http_method;
402: 
403:     }
404: 
405:   }
406: 
407: }
408: 
409: 
API documentation generated by ApiGen 2.8.0