Permalink
Browse files

Pulls out web services into a plugin

  • Loading branch information...
cash committed Feb 9, 2013
1 parent 64668db commit 9d6a8679c78a2d6098c16375075aabbe4ff75326
View
@@ -36,6 +36,7 @@
!/mod/twitter/
!/mod/twitter_api/
!/mod/uservalidationbyemail/
+!/mod/web_services/
!/mod/zaudio/
# ignore IDE/hidden/OS cache files
@@ -2,26 +2,14 @@
/**
* Services handler.
*
- * This file dispatches requests to web services. It is called via a URL rewrite
- * in .htaccess from http://site/services/api/handler/response_format/request.
- * The first element after 'services/api/' is the service handler name as
- * registered by {@link register_service_handler()}.
- *
- * The remaining string is then passed to the {@link service_handler()}
- * which explodes by /, extracts the first element as the response format
- * (viewtype), and then passes the remaining array to the service handler
- * function registered by {@link register_service_handler()}.
- *
- * If a service handler isn't found, a 404 header is sent.
- *
- * @package Elgg.Core
- * @subpackage WebServices
- * @link http://docs.elgg.org/Tutorials/WebServices
+ * @deprecated 1.9 Update your .htaccess to remove the service handler
*/
require_once(dirname(dirname(__FILE__)) . "/start.php");
$handler = get_input('handler');
$request = get_input('request');
+elgg_deprecated_notice("Update your .htaccess file to remove the service handler", 1.9);
+
service_handler($handler, $request);
View
@@ -108,7 +108,6 @@
'users.php',
'upgrade.php',
'views.php',
- 'web_services.php',
'widgets.php',
'xml.php',
View
@@ -110,8 +110,6 @@ RewriteRule ^action\/([A-Za-z0-9\_\-\/]+)$ engine/handlers/action_handler.php?ac
RewriteRule ^cache\/(.*)$ engine/handlers/cache_handler.php?request=$1&%{QUERY_STRING} [L]
-RewriteRule ^services\/api\/([A-Za-z0-9\_\-]+)\/(.*)$ engine/handlers/service_handler.php?handler=$1&request=$2&%{QUERY_STRING} [L]
-
RewriteRule ^export\/([A-Za-z]+)\/([0-9]+)\/?$ engine/handlers/export_handler.php?view=$1&guid=$2 [L]
RewriteRule ^export\/([A-Za-z]+)\/([0-9]+)\/([A-Za-z]+)\/([A-Za-z0-9\_]+)\/$ engine/handlers/export_handler.php?view=$1&guid=$2&type=$3&idname=$4 [L]
@@ -799,7 +799,7 @@ protected function finishBootstraping($step) {
'pam.php', 'plugins.php',
'private_settings.php', 'relationships.php', 'river.php',
'sites.php', 'statistics.php', 'tags.php', 'user_settings.php',
- 'users.php', 'upgrade.php', 'web_services.php',
+ 'users.php', 'upgrade.php',
'widgets.php', 'xml.php', 'deprecated-1.7.php',
'deprecated-1.8.php', 'deprecated-1.9.php'
);
@@ -0,0 +1,7 @@
+Web Services
+=========================
+This plugin provides the web services API that was packaged with Elgg core from
+version 1.0-1.8. Other plugins can expose functions as web services for
+integration with other platforms or applications.
+
+Documentation is available at http://docs.elgg.org/wiki/Web_Services
@@ -0,0 +1,24 @@
+<?php
+/**
+ * The core language file is in /languages/en.php and each plugin has its
+ * language files in a languages directory. To change a string, copy the
+ * mapping into this file.
+ *
+ * For example, to change the blog Tools menu item
+ * from "Blog" to "Rantings", copy this pair:
+ * 'blog' => "Blog",
+ * into the $mapping array so that it looks like:
+ * 'blog' => "Rantings",
+ *
+ * Follow this pattern for any other string you want to change. Make sure this
+ * plugin is lower in the plugin list than any plugin that it is modifying.
+ *
+ * If you want to add languages other than English, name the file according to
+ * the language's ISO 639-1 code: http://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
+ */
+
+$mapping = array(
+ 'string:here' => 'Display string here',
+);
+
+add_translation('en', $mapping);
@@ -0,0 +1,76 @@
+<?php
+/**
+ * A library for managing users of the web services API
+ */
+
+// API key functions /////////////////////////////////////////////////////////////////////
+
+/**
+ * Generate a new API user for a site, returning a new keypair on success.
+ *
+ * @param int $site_guid The GUID of the site. (default is current site)
+ *
+ * @return stdClass object or false
+ */
+function create_api_user($site_guid) {
+ global $CONFIG;
+
+ if (!isset($site_guid)) {
+ $site_guid = $CONFIG->site_id;
+ }
+
+ $site_guid = (int)$site_guid;
+
+ $public = sha1(rand() . $site_guid . microtime());
+ $secret = sha1(rand() . $site_guid . microtime() . $public);
+
+ $insert = insert_data("INSERT into {$CONFIG->dbprefix}api_users
+ (site_guid, api_key, secret) values
+ ($site_guid, '$public', '$secret')");
+
+ if ($insert) {
+ return get_api_user($site_guid, $public);
+ }
+
+ return false;
+}
+
+/**
+ * Find an API User's details based on the provided public api key.
+ * These users are not users in the traditional sense.
+ *
+ * @param int $site_guid The GUID of the site.
+ * @param string $api_key The API Key
+ *
+ * @return mixed stdClass representing the database row or false.
+ */
+function get_api_user($site_guid, $api_key) {
+ global $CONFIG;
+
+ $api_key = sanitise_string($api_key);
+ $site_guid = (int)$site_guid;
+
+ $query = "SELECT * from {$CONFIG->dbprefix}api_users"
+ . " where api_key='$api_key' and site_guid=$site_guid and active=1";
+
+ return get_data_row($query);
+}
+
+/**
+ * Revoke an api user key.
+ *
+ * @param int $site_guid The GUID of the site.
+ * @param string $api_key The API Key (public).
+ *
+ * @return bool
+ */
+function remove_api_user($site_guid, $api_key) {
+ global $CONFIG;
+
+ $keypair = get_api_user($site_guid, $api_key);
+ if ($keypair) {
+ return delete_data("DELETE from {$CONFIG->dbprefix}api_users where id={$keypair->id}");
+ }
+
+ return false;
+}
@@ -0,0 +1,162 @@
+<?php
+/**
+ * A library for building an API client
+ *
+ * Load the library 'elgg:ws:client' to use the functions in this library
+ */
+
+/**
+ * Send a raw API call to an elgg api endpoint.
+ *
+ * @param array $keys The api keys.
+ * @param string $url URL of the endpoint.
+ * @param array $call Associated array of "variable" => "value"
+ * @param string $method GET or POST
+ * @param string $post_data The post data
+ * @param string $content_type The content type
+ *
+ * @return string
+ */
+function send_api_call(array $keys, $url, array $call, $method = 'GET', $post_data = '',
+$content_type = 'application/octet-stream') {
+
+ global $CONFIG;
+
+ $headers = array();
+ $encoded_params = array();
+
+ $method = strtoupper($method);
+ switch (strtoupper($method)) {
+ case 'GET' :
+ case 'POST' :
+ break;
+ default:
+ $msg = elgg_echo('NotImplementedException:CallMethodNotImplemented', array($method));
+ throw new NotImplementedException($msg);
+ }
+
+ // Time
+ $time = time();
+
+ // Nonce
+ $nonce = uniqid('');
+
+ // URL encode all the parameters
+ foreach ($call as $k => $v) {
+ $encoded_params[] = urlencode($k) . '=' . urlencode($v);
+ }
+
+ $params = implode('&', $encoded_params);
+
+ // Put together the query string
+ $url = $url . "?" . $params;
+
+ // Construct headers
+ $posthash = "";
+ if ($method == 'POST') {
+ $posthash = calculate_posthash($post_data, 'md5');
+ }
+
+ if ((isset($keys['public'])) && (isset($keys['private']))) {
+ $headers['X-Elgg-apikey'] = $keys['public'];
+ $headers['X-Elgg-time'] = $time;
+ $headers['X-Elgg-nonce'] = $nonce;
+ $headers['X-Elgg-hmac-algo'] = 'sha1';
+ $headers['X-Elgg-hmac'] = calculate_hmac('sha1',
+ $time,
+ $nonce,
+ $keys['public'],
+ $keys['private'],
+ $params,
+ $posthash
+ );
+ }
+ if ($method == 'POST') {
+ $headers['X-Elgg-posthash'] = $posthash;
+ $headers['X-Elgg-posthash-algo'] = 'md5';
+
+ $headers['Content-type'] = $content_type;
+ $headers['Content-Length'] = strlen($post_data);
+ }
+
+ // Opt array
+ $http_opts = array(
+ 'method' => $method,
+ 'header' => serialise_api_headers($headers)
+ );
+ if ($method == 'POST') {
+ $http_opts['content'] = $post_data;
+ }
+
+ $opts = array('http' => $http_opts);
+
+ // Send context
+ $context = stream_context_create($opts);
+
+ // Send the query and get the result and decode.
+ elgg_log("APICALL: $url");
+ $results = file_get_contents($url, false, $context);
+
+ return $results;
+}
+
+/**
+ * Send a GET call
+ *
+ * @param string $url URL of the endpoint.
+ * @param array $call Associated array of "variable" => "value"
+ * @param array $keys The keys dependant on chosen authentication method
+ *
+ * @return string
+ */
+function send_api_get_call($url, array $call, array $keys) {
+ return send_api_call($keys, $url, $call);
+}
+
+/**
+ * Send a GET call
+ *
+ * @param string $url URL of the endpoint.
+ * @param array $call Associated array of "variable" => "value"
+ * @param array $keys The keys dependant on chosen authentication method
+ * @param string $post_data The post data
+ * @param string $content_type The content type
+ *
+ * @return string
+ */
+function send_api_post_call($url, array $call, array $keys, $post_data,
+$content_type = 'application/octet-stream') {
+
+ return send_api_call($keys, $url, $call, 'POST', $post_data, $content_type);
+}
+
+/**
+ * Return a key array suitable for the API client using the standard
+ * authentication method based on api-keys and secret keys.
+ *
+ * @param string $secret_key Your secret key
+ * @param string $api_key Your api key
+ *
+ * @return array
+ */
+function get_standard_api_key_array($secret_key, $api_key) {
+ return array('public' => $api_key, 'private' => $secret_key);
+}
+
+/**
+ * Utility function to serialise a header array into its text representation.
+ *
+ * @param array $headers The array of headers "key" => "value"
+ *
+ * @return string
+ * @access private
+ */
+function serialise_api_headers(array $headers) {
+ $headers_str = "";
+
+ foreach ($headers as $k => $v) {
+ $headers_str .= trim($k) . ": " . trim($v) . "\r\n";
+ }
+
+ return trim($headers_str);
+}
Oops, something went wrong.

0 comments on commit 9d6a867

Please sign in to comment.