7.x-2.x branch
Testing functionality for Mollom module.
| Name | Description |
|---|---|
| mollom_test_server_check_captcha | API callback for mollom.checkCaptcha to validate a CAPTCHA response. |
| mollom_test_server_check_content | API callback for mollom.checkContent to perform textual analysis. |
| mollom_test_server_check_content_blacklist | Checks a string against blacklisted terms. |
| mollom_test_server_get_captcha | API callback for mollom.getImageCaptcha to fetch a CATPCHA image. |
| mollom_test_server_menu | Implements hook_menu(). |
| mollom_test_server_rest_add_xml | |
| mollom_test_server_rest_blacklist | REST callback for Blacklist API. |
| mollom_test_server_rest_captcha | REST callback to for CAPTCHAs. |
| mollom_test_server_rest_content | REST callback for mollom.checkContent to perform textual analysis. |
| mollom_test_server_rest_deliver | Delivery callback for REST API endpoints. |
| mollom_test_server_rest_get_auth_header | Returns the parsed HTTP Authorization request header as an array. |
| mollom_test_server_rest_get_parameters | Returns HTTP request query parameters for the current request. |
| mollom_test_server_rest_send_feedback | REST callback for mollom.sendFeedback to send feedback for a moderated post. |
| mollom_test_server_rest_site | REST callback for CRUD site operations. |
| mollom_test_server_rest_validate_auth | Returns whether the OAuth request signature is valid. |
- <?php
-
- /**
- * @file
- * Testing functionality for Mollom module.
- */
-
- /**
- * Implements hook_menu().
- */
- function mollom_test_server_menu() {
- $path = 'mollom-test/rest/v1';
- $base_args = count(explode('/', $path)) - 1;
- // @todo Consider to use a generic page callback, passing arg(3), the resource
- // type, and optionally arg(4), the resource, as argument. This would allow
- // us to use PHP Exceptions to throw different status codes and errors. Make
- // that page callback dynamically switch the delivery callback (for JSON).
- $base = array(
- 'access callback' => TRUE,
- 'type' => MENU_CALLBACK,
- 'delivery callback' => 'mollom_test_server_rest_deliver',
- );
-
- $items[$path . '/site'] = $base + array(
- 'page callback' => 'mollom_test_server_rest_site',
- );
- $items[$path . '/content'] = $base + array(
- 'page callback' => 'mollom_test_server_rest_content',
- );
- $items[$path . '/captcha'] = $base + array(
- 'page callback' => 'mollom_test_server_rest_captcha',
- );
- $items[$path . '/feedback'] = $base + array(
- 'page callback' => 'mollom_test_server_rest_send_feedback',
- );
- $items[$path . '/blacklist/%'] = $base + array(
- 'page callback' => 'mollom_test_server_rest_blacklist',
- 'page arguments' => array($base_args + 2),
- );
- // @todo Whitelist endpoints.
-
- return $items;
- }
-
- /**
- * Returns HTTP request query parameters for the current request.
- *
- * @see Mollom::httpBuildQuery()
- * @see http://php.net/manual/en/wrappers.php.php
- */
- function mollom_test_server_rest_get_parameters() {
- $data = &drupal_static(__FUNCTION__);
-
- if (isset($data)) {
- return $data;
- }
-
- if ($_SERVER['REQUEST_METHOD'] == 'GET' || $_SERVER['REQUEST_METHOD'] == 'HEAD') {
- $data = Mollom::httpParseQuery($_SERVER['QUERY_STRING']);
- // Remove $_GET['q'].
- unset($data['q']);
- }
- elseif ($_SERVER['REQUEST_METHOD'] == 'POST' || $_SERVER['REQUEST_METHOD'] == 'PUT') {
- $data = Mollom::httpParseQuery(file_get_contents('php://input'));
- }
- return $data;
- }
-
- /**
- * Returns the parsed HTTP Authorization request header as an array.
- */
- function mollom_test_server_rest_get_auth_header() {
- $header = &drupal_static(__FUNCTION__);
-
- if (isset($header)) {
- return $header;
- }
-
- $header = array();
- if (function_exists('apache_request_headers')) {
- $headers = apache_request_headers();
- if (isset($headers['Authorization'])) {
- $input = $headers['Authorization'];
- }
- }
- elseif (isset($_SERVER['HTTP_AUTHORIZATION'])) {
- $input = $_SERVER['HTTP_AUTHORIZATION'];
- }
- if (isset($input)) {
- preg_match_all('@([^, =]+)="([^"]*)"@', $input, $header);
- $header = array_combine($header[1], $header[2]);
- }
- return $header;
- }
-
- /**
- * Delivery callback for REST API endpoints.
- */
- function mollom_test_server_rest_deliver($page_callback_result) {
- drupal_add_http_header('Content-Type', 'application/xml; charset=utf-8');
-
- $xml = new DOMDocument('1.0', 'utf-8');
- $element = $xml->createElement('response');
-
- // Append status response parameters.
- // @todo Add support for custom codes (redirect/refresh) + error messages.
- $code = 200;
- if (!is_array($page_callback_result) && $page_callback_result !== TRUE) {
- switch ($page_callback_result) {
- case MENU_NOT_FOUND:
- $code = 404;
- $message = 'Not found';
- break;
-
- case Mollom::AUTH_ERROR:
- $code = 401;
- $message = 'Unauthorized';
- break;
-
- default:
- $code = 400;
- $message = 'Bad request';
- break;
- }
- }
- $status = array(
- 'code' => $code,
- );
- if (isset($message)) {
- $status['message'] = $message;
- }
- mollom_test_server_rest_add_xml($xml, $element, $status);
-
- // Append other response parameters.
- if (is_array($page_callback_result)) {
- mollom_test_server_rest_add_xml($xml, $element, $page_callback_result);
- }
-
- $xml->appendChild($element);
- print $xml->saveXML();
-
- // Perform end-of-request tasks.
- drupal_page_footer();
- }
-
- function mollom_test_server_rest_add_xml(DOMDocument $doc, DOMNode $parent, $data, $key = NULL) {
- if (is_scalar($data)) {
- // Mollom REST API always uses integers instead of Booleans due to varying
- // implementations of JSON protocol across client platforms/frameworks.
- if (is_bool($data)) {
- $data = (int) $data;
- }
-
- $element = $doc->createTextNode($data);
- $parent->appendChild($element);
- }
- else {
- foreach ($data as $property => $value) {
- $key = (is_numeric($property) ? 'item' : $property);
- $element = $doc->createElement($key);
- $parent->appendChild($element);
- mollom_test_server_rest_add_xml($doc, $element, $value, $key);
- }
- }
- }
-
- /**
- * Returns whether the OAuth request signature is valid.
- */
- function mollom_test_server_rest_validate_auth() {
- $data = mollom_test_server_rest_get_parameters();
- $header = mollom_test_server_rest_get_auth_header();
- $sites = variable_get('mollom_test_server_site', array());
-
- $sent_signature = $header['oauth_signature'];
- unset($header['oauth_signature']);
-
- $base_string = implode('&', array(
- $_SERVER['REQUEST_METHOD'],
- Mollom::rawurlencode($GLOBALS['base_url'] . '/' . $_GET['q']),
- Mollom::rawurlencode(Mollom::httpBuildQuery($data + $header)),
- ));
- $time = $header['oauth_timestamp'];
- $nonce = $header['oauth_nonce'];
-
- if (!isset($sites[$header['oauth_consumer_key']]['privateKey'])) {
- return FALSE;
- }
- $privateKey = $sites[$header['oauth_consumer_key']]['privateKey'];
- $key = Mollom::rawurlencode($privateKey) . '&' . '';
-
- $signature = rawurlencode(base64_encode(hash_hmac('sha1', $base_string, $key, TRUE)));
-
- return $signature === $sent_signature;
- }
-
- /**
- * REST callback for CRUD site operations.
- *
- * @param $publicKey
- * (optional) The public key of a site.
- * @param $delete
- * (optional) Whether to delete the site with $publicKey.
- */
- function mollom_test_server_rest_site($publicKey = NULL, $delete = FALSE) {
- $data = mollom_test_server_rest_get_parameters();
-
- $bin = 'mollom_test_server_site';
- $sites = variable_get($bin, array());
-
- if (isset($publicKey)) {
- // Validate authentication.
- if (!mollom_test_server_rest_validate_auth()) {
- return Mollom::AUTH_ERROR;
- }
- // Check whether publicKey exists.
- if (!isset($sites[$publicKey])) {
- return MENU_NOT_FOUND;
- }
- }
-
- if ($_SERVER['REQUEST_METHOD'] == 'GET') {
- // Return existing site.
- if (isset($publicKey)) {
- $response = $sites[$publicKey];
- }
- // Return list of existing sites.
- else {
- $response = array(
- 'list' => array_values($sites),
- 'listCount' => count($sites),
- 'listOffset' => 0,
- 'listTotal' => count($sites),
- );
- return $response;
- }
- }
- else {
- // Update site.
- if (isset($publicKey) && !$delete) {
- $sites[$publicKey] = $data + $sites[$publicKey];
- variable_set($bin, $sites);
- $response = $sites[$publicKey];
- }
- // Create new site.
- // Authentication is ignored in this case.
- elseif (!$delete) {
- $data['publicKey'] = $publicKey = md5(rand() . REQUEST_TIME);
- $data['privateKey'] = $privateKey = md5(rand() . REQUEST_TIME);
- // Apply default values.
- $data += array(
- 'url' => '',
- 'email' => '',
- 'languages' => array(),
- 'subscriptionType' => 0, // Mollom Free.
- // Client version info is not defined by default.
- );
- $sites[$publicKey] = $data;
- variable_set($bin, $sites);
- $response = $data;
- }
- // Delete site.
- else {
- unset($sites[$publicKey]);
- variable_set($bin, $sites);
- return TRUE;
- }
- }
- return array('site' => $response);
- }
-
- /**
- * REST callback for mollom.checkContent to perform textual analysis.
- */
- function mollom_test_server_rest_content($contentId = NULL) {
- $data = mollom_test_server_rest_get_parameters();
- if ($_SERVER['REQUEST_METHOD'] == 'GET') {
- // @todo List/read content.
- if (empty($contentId)) {
- return FALSE;
- }
- return FALSE;
- }
- else {
- // Content ID in request parameters must match the one in path.
- if (isset($data['id']) && $data['id'] != $contentId) {
- return FALSE;
- }
- if (isset($contentId)) {
- $data['id'] = $contentId;
- }
- }
-
- // Default POST: Create or update content and check it.
- return array('content' => mollom_test_server_check_content($data));
- }
-
- /**
- * REST callback to for CAPTCHAs.
- */
- function mollom_test_server_rest_captcha($captchaId = NULL) {
- $data = mollom_test_server_rest_get_parameters();
- if ($_SERVER['REQUEST_METHOD'] == 'GET') {
- // There is no GET /captcha[/{captchaId}].
- return FALSE;
- }
- else {
- // CAPTCHA ID in request parameters must match the one in path.
- if (isset($data['id']) && $data['id'] != $captchaId) {
- return FALSE;
- }
- // Verify CAPTCHA.
- if (isset($captchaId)) {
- $data['id'] = $captchaId;
- $response = mollom_test_server_check_captcha($data);
- if (!is_array($response)) {
- return $response;
- }
- return array('captcha' => $response);
- }
- }
- // Create a new CAPTCHA resource.
- return array('captcha' => mollom_test_server_get_captcha($data));
- }
-
- /**
- * REST callback for Blacklist API.
- *
- * @param $public_key
- * The public key of a site.
- *
- * @todo Abstract actual functionality like other REST handlers.
- */
- function mollom_test_server_rest_blacklist($public_key, $entryId = NULL, $delete = FALSE) {
- if (empty($public_key)) {
- return FALSE;
- }
- $data = mollom_test_server_rest_get_parameters();
-
- // Prepare text value.
- if (isset($data['value'])) {
- $data['value'] = drupal_strtolower(trim($data['value']));
- }
-
- $bin = 'mollom_test_server_blacklist_' . $public_key;
- $entries = variable_get($bin, array());
-
- if ($_SERVER['REQUEST_METHOD'] == 'GET') {
- // List blacklist entries.
- if (empty($entryId)) {
- $response = array();
- // Remove deleted entries (== FALSE).
- $entries = array_filter($entries);
- $response['list'] = $entries;
- // @todo Not required yet.
- $response['listCount'] = count($entries);
- $response['listOffset'] = 0;
- $response['listTotal'] = count($entries);
- return $response;
- }
- // Read a single entry.
- else {
- // Check whether the entry exists and was not deleted.
- if (!empty($entries[$entryId])) {
- return array('entry' => $entries[$entryId]);
- }
- else {
- return MENU_NOT_FOUND;
- }
- }
- }
- else {
- // Update an existing entry.
- if (isset($entryId)) {
- // Entry ID must match.
- if (isset($data['id']) && $data['id'] != $entryId) {
- return FALSE;
- }
- // Check that the entry was not deleted.
- if (empty($entries[$entryId])) {
- return MENU_NOT_FOUND;
- }
- // Entry ID cannot be updated.
- unset($data['id']);
- $entries[$entryId] = $data;
- variable_set($bin, $entries);
- $response = $data;
- $response['id'] = $entryId;
- return array('entry' => $response);
- }
- // Create a new entry.
- elseif (!$delete) {
- $entryId = max(array_keys($entries)) + 1;
- $data['id'] = $entryId;
- $entries[$entryId] = $data;
- variable_set($bin, $entries);
-
- $response = $data;
- return array('entry' => $response);
- }
- // Delete an existing entry.
- else {
- // Check that the entry was not deleted already.
- if (!empty($entries[$entryId])) {
- $entries[$entryId] = FALSE;
- variable_set($bin, $entries);
- return TRUE;
- }
- else {
- return MENU_NOT_FOUND;
- }
- }
- }
- }
-
- /**
- * REST callback for mollom.sendFeedback to send feedback for a moderated post.
- */
- function mollom_test_server_rest_send_feedback() {
- $data = mollom_test_server_rest_get_parameters();
- // A resource ID is required.
- if (empty($data['contentId']) && empty($data['captchaId'])) {
- return 400;
- }
-
- // The feedback is valid if the supplied reason is one of the supported
- // strings. Otherwise, it's a bad request.
- $storage = variable_get('mollom_test_server_feedback', array());
- $storage[] = $data;
- variable_set('mollom_test_server_feedback', $storage);
-
- $result = in_array($data['reason'], array('spam', 'profanity', 'quality', 'unwanted', 'approve', 'delete'));
- return $result ? TRUE : 400;
- }
-
- /**
- * API callback for mollom.checkContent to perform textual analysis.
- *
- * @todo Add support for 'redirect' and 'refresh' values.
- */
- function mollom_test_server_check_content($data) {
- $response = array();
-
- // If only a single value for checks is passed, it is a string.
- if (isset($data['checks']) && is_string($data['checks'])) {
- $data['checks'] = array($data['checks']);
- }
-
- $header = mollom_test_server_rest_get_auth_header();
- $publicKey = $header['oauth_consumer_key'];
-
- // Fetch blacklist.
- $blacklist = variable_get('mollom_test_server_blacklist_' . $publicKey, array());
-
- $post = implode('\n', array_intersect_key($data, array('postTitle' => 1, 'postBody' => 1)));
-
- $update = isset($data['stored']);
-
- // Spam filter: Check post_title and post_body for ham, spam, or unsure.
- if (!$update && (!isset($data['checks']) || in_array('spam', $data['checks']))) {
- $spam = FALSE;
- $ham = FALSE;
- // 'spam' always has precedence.
- if (strpos($post, 'spam') !== FALSE) {
- $spam = TRUE;
- }
- // Otherwise, check for 'ham'.
- elseif (strpos($post, 'ham') !== FALSE) {
- $ham = TRUE;
- }
- // Lastly, take a forced 'unsure' into account.
- elseif (strpos($post, 'unsure') !== FALSE) {
- // Differentiate between binary unsure mode.
- if (!isset($data['unsure']) || $data['unsure']) {
- $spam = TRUE;
- $ham = TRUE;
- }
- else {
- $spam = TRUE;
- $ham = FALSE;
- }
- }
- // Check blacklist.
- if ($matches = mollom_test_server_check_content_blacklist($post, $blacklist, 'spam')) {
- $spam = TRUE;
- $ham = FALSE;
- $response['reason'] = 'blacklist';
- $response['blacklistSpam'] = $matches;
- }
-
- if ($spam && $ham) {
- $response['spamScore'] = 0.5;
- $response['spamClassification'] = 'unsure';
- $qualityScore = 0.5;
- }
- elseif ($spam) {
- $response['spamScore'] = 1.0;
- $response['spamClassification'] = 'spam';
- $qualityScore = 0.0;
- }
- elseif ($ham) {
- $response['spamScore'] = 0.0;
- $response['spamClassification'] = 'ham';
- $qualityScore = 1.0;
- }
- else {
- $response['spamScore'] = 0.5;
- $response['spamClassification'] = 'unsure';
- $qualityScore = NULL;
- }
- // In case a previous spam check was unsure and a CAPTCHA was solved, the
- // result is supposed to be ham.
- $captcha_sessions = variable_get('mollom_test_server_check_captcha_sessions', array());
- if (!empty($data['captchaId']) && !empty($captcha_sessions[$data['captchaId']])) {
- $response['spamScore'] = 0.0;
- $response['spamClassification'] = 'ham';
- }
- }
-
- // Quality filter.
- if (isset($data['checks']) && in_array('quality', $data['checks'])) {
- if (isset($qualityScore)) {
- $response['qualityScore'] = $qualityScore;
- }
- else {
- $response['qualityScore'] = 0;
- }
- }
-
- // Profanity filter.
- if (isset($data['checks']) && in_array('profanity', $data['checks'])) {
- $profanityScore = 0.0;
- if (strpos($post, 'profanity') !== FALSE) {
- $profanityScore = 1.0;
- }
- // Check blacklist.
- if ($matches = mollom_test_server_check_content_blacklist($post, $blacklist, 'profanity')) {
- $profanityScore = 1.0;
- $response['blacklistProfanity'] = $matches;
- }
- $response['profanityScore'] = $profanityScore;
- }
-
- // Language detection.
- if (isset($data['checks']) && in_array('language', $data['checks'])) {
- $languages = array();
- preg_match_all('@\blang-(..)\b@', $post, $matches);
- if (empty($matches[1])) {
- $languages[] = array(
- 'languageCode' => 'zxx',
- 'languageScore' => 1.0,
- );
- }
- elseif (count($matches[1]) > 3) {
- $languages[] = array(
- 'languageCode' => LANGUAGE_NONE,
- 'languageScore' => 1.0,
- );
- }
- else {
- $languageScore = 1 / count($matches[1]);
- foreach ($matches[1] as $language) {
- $languages[] = array(
- 'languageCode' => $language,
- 'languageScore' => $languageScore,
- );
- }
- }
- $response['languages'] = $languages;
- $response['langDebug'] = $matches;
- }
-
- $storage = variable_get('mollom_test_server_content', array());
- $contentId = (!empty($data['id']) ? $data['id'] : md5(mt_rand()));
- if (isset($storage[$contentId])) {
- $storage[$contentId] = array_merge($storage[$contentId], $data);
- }
- else {
- $storage[$contentId] = $data;
- }
- if ($update) {
- $response = array_merge($storage[$contentId], $response);
- }
- $response['id'] = $contentId;
- variable_set('mollom_test_server_content', $storage);
-
- return $response;
- }
-
- /**
- * Checks a string against blacklisted terms.
- */
- function mollom_test_server_check_content_blacklist($string, $blacklist, $reason) {
- $terms = array();
- foreach ($blacklist as $entry) {
- if ($entry['reason'] == $reason) {
- $term = preg_quote($entry['value']);
- if ($entry['match'] == 'exact') {
- $term = '\b' . $term . '\b';
- }
- $terms[] = $term;
- }
- }
- if (!empty($terms)) {
- $terms = '/(' . implode('|', $terms) . ')/';
- preg_match_all($terms, strtolower($string), $matches);
- return $matches[1];
- }
- return array();
- }
-
- /**
- * API callback for mollom.getImageCaptcha to fetch a CATPCHA image.
- */
- function mollom_test_server_get_captcha($data) {
- $response = array();
-
- // Return a HTTPS URL if 'ssl' parameter was passed.
- $base_url = $GLOBALS['base_url'];
- if (!empty($data['ssl'])) {
- $base_url = str_replace('http', 'https', $base_url);
- }
- $response['url'] = $base_url . '/' . drupal_get_path('module', 'mollom') . '/images/powered-by-mollom-2.gif';
-
- $storage = variable_get('mollom_test_server_captcha', array());
- $captchaId = (!empty($data['id']) ? $data['id'] : md5(mt_rand()));
- $storage[$captchaId] = $data;
- $response['id'] = $captchaId;
- variable_set('mollom_test_server_captcha', $storage);
-
- return $response;
- }
-
- /**
- * API callback for mollom.checkCaptcha to validate a CAPTCHA response.
- *
- * @todo Add support for 'redirect' and 'refresh' values.
- */
- function mollom_test_server_check_captcha($data) {
- $response = array();
-
- if (isset($data['solution']) && $data['solution'] == 'correct') {
- $response['solved'] = TRUE;
- }
- else {
- $response['solved'] = FALSE;
- $response['reason'] = '';
- }
-
- $storage = variable_get('mollom_test_server_captcha', array());
- $captchaId = $data['id'];
- if (!isset($storage[$captchaId])) {
- return MENU_NOT_FOUND;
- }
- $storage[$captchaId] = $data;
- $response['id'] = $captchaId;
- variable_set('mollom_test_server_captcha', $storage);
-
- $captcha_sessions = variable_get('mollom_test_server_check_captcha_sessions', array());
- $captcha_sessions[$captchaId] = $response['solved'];
- variable_set('mollom_test_server_check_captcha_sessions', $captcha_sessions);
-
- return $response;
- }
-
-