getMessage()); } } /** * Get method documentation file contents (stuff within the XML file). * If you're looking for a parsed representation, use services/apiref/method. */ public static function docs($service_name) { if (!self::exists($service_name)) throw new Exception(); try { return file_get_contents("$service_name.xml", true); } catch (Exception $e) { throw new Exception("Missing documentation file: $service_name.xml"); } } /** * Execute the method and return the result. * * OKAPI methods return OkapiHttpResponses, but some MAY also return * PHP objects (see OkapiRequest::construct_inside_request for details). * * If $request must be consistent with given method's options (must * include Consumer and Token, if they are required). */ public static function call($service_name, OkapiRequest $request) { Okapi::init_internals(); if (!self::exists($service_name)) throw new Exception("Method does not exist: '$service_name'"); $options = self::options($service_name); if ($options['min_auth_level'] >= 2 && $request->consumer == null) { throw new Exception("Method '$service_name' called with mismatched OkapiRequest: ". "\$request->consumer MAY NOT be empty for Level 2 and Level 3 methods. Provide ". "a dummy Consumer if you have to."); } if ($options['min_auth_level'] >= 3 && $request->token == null) { throw new Exception("Method '$service_name' called with mismatched OkapiRequest: ". "\$request->token MAY NOT be empty for Level 3 methods."); } $time_started = microtime(true); Okapi::gettext_domain_init(); try { require_once($GLOBALS['rootpath']."okapi/$service_name.php"); $response = call_user_func(array('\\okapi\\'. str_replace('/', '\\', $service_name).'\\WebService', 'call'), $request); Okapi::gettext_domain_restore(); } catch (Exception $e) { Okapi::gettext_domain_restore(); throw $e; } $runtime = microtime(true) - $time_started; # Log the request to the stats table. Only valid requests (these which didn't end up # with an exception) are logged. self::save_stats($service_name, $request, $runtime); return $response; } /** * For internal use only. The stats table can be used to store any kind of * runtime-stats data, i.e. not only regarding services. This is a special * version of save_stats which saves runtime stats under the name of $extra_name. * Note, that $request can be null. */ public static function save_stats_extra($extra_name, $request, $runtime) { self::save_stats("extra/".$extra_name, $request, $runtime); } private static function save_stats($service_name, $request, $runtime) { # Getting rid of nulls. MySQL PRIMARY keys cannot contain nullable columns. # Temp table doesn't have primary key, but other stats tables (which are # dependant on stats table) - do. if ($request !== null) { $consumer_key = ($request->consumer != null) ? $request->consumer->key : 'anonymous'; $user_id = (($request->token != null) && ($request->token instanceof OkapiAccessToken)) ? $request->token->user_id : -1; if ($request->is_http_request() && ($service_name[0] == 's')) # 's' for "services/", we don't want "extra/" included $calltype = 'http'; else $calltype = 'internal'; } else { $consumer_key = 'internal'; $user_id = -1; $calltype = 'internal'; } Db::execute(" insert into okapi_stats_temp (`datetime`, consumer_key, user_id, service_name, calltype, runtime) values ( now(), '".mysql_real_escape_string($consumer_key)."', '".mysql_real_escape_string($user_id)."', '".mysql_real_escape_string($service_name)."', '".mysql_real_escape_string($calltype)."', '".mysql_real_escape_string($runtime)."' ); "); } }