Index: json_server.module =================================================================== RCS file: /cvs/drupal-contrib/contributions/modules/json_server/json_server.module,v retrieving revision 1.8.4.2 diff -u -r1.8.4.2 json_server.module --- json_server.module 4 May 2010 20:00:36 -0000 1.8.4.2 +++ json_server.module 24 Sep 2010 23:27:10 -0000 @@ -23,7 +23,7 @@ * Implementation of hook_server_error(). */ function json_server_server_error($message) { - return array("#error" => TRUE, "#message" => $message); + return array("error" => TRUE, "#message" => $message); } @@ -31,42 +31,82 @@ * Implementation of hook_server(). */ function json_server_server() { -if (!isset($_POST)) { - return drupal_to_js(array('#error' => TRUE, '#data' => "JSON server accepts POST requests only.")); -} + // Check if JSONP is active and callback is set + $json_server_jsonp = variable_get('json_server_jsonp', FALSE); + + if ($json_server_jsonp) { + $client_data = $_REQUEST; + $request_method = $_REQUEST['method']; + unset($_REQUEST['q']); + unset($_REQUEST['method']); + + $callback = variable_get('json_server_jsonp_callback', 'callback'); + } + else { + $client_data = $_POST; + $request_method = $_POST['method']; + unset($_POST['q']); + unset($_POST['method']); + } + + if (!$client_data) { + return drupal_to_js(array('#error' => TRUE, '#data' => "JSON server accepts POST requests only.")); + } $methods = services_get_all(); services_strip_hashes($methods); - $request = drupal_parse_json($_POST['method']); - $args = array(); + $args = array(); foreach ($methods as $method) { - if ($method['method'] == $request) { - unset($_POST['q']); - unset($_POST['method']); + if ($method['method'] == $request_method) { $args = array(); foreach($method['args'] as $arg) { - if(isset($_POST[$arg['name']])) { - $args[] = drupal_parse_json($_POST[$arg['name']]); + if(isset($client_data[$arg['name']])) { + $data = drupal_parse_json($client_data[$arg['name']]); + + // only enable when using jsonp. I do not know the implications for json calls + if ($json_server_jsonp) { + drupal_alter('json_data_' . str_replace('.', '_', $request_method), &$data); + } + $args[] = $data; } - elseif($arg['optional'] == 0) { - return drupal_to_js(array("#error" => TRUE, "#data" => "Argument ". $arg['name'] ." not recieved")); + elseif(!$arg['optional']) { + $response = array("#error" => TRUE, "#data" => "Argument ". $arg['name'] ." not recieved"); } else { $args[$arg['name']] = NULL; } } + $result = services_method_call($method['method'], $args); - if (is_array($result) && $result['error'] === TRUE) - return drupal_to_js(array('#error' => TRUE, '#data' => $result['message'])); - return drupal_to_js(array('#error' => FALSE, '#data' => $result)); + // clears the message or error when doing any processing + drupal_get_messages(); + + if (is_array($result) && $result['error'] === TRUE) { + $response = array('#error' => TRUE, '#data' => $result['message']); + } + else { + $response = array('#error' => FALSE, '#data' => $result); + } } } - return drupal_to_js(array('#error' => TRUE, '#data' => "Invalid method $request")); + if (!isset($response)) { + $response = array('#error' => TRUE, '#data' => "Invalid method $request_method"); + } + + if ($json_server_jsonp && isset($client_data[$callback])) { + header('Content-Type: application/javascript'); + header('Access-Control-Allow-Origin: *'); + header('Access-Control-Allow-Methods: GET'); + + return $client_data[$callback] ."(". json_server_encode_json($response) .");"; + } else { + // We are returning JSON. + return drupal_json($response); + } } - /** * Load the needed assets to run the server via js. @@ -78,6 +118,10 @@ drupal_add_js(array("baseurl" => $base_url ."/"), 'setting'); } + +/** + * JSON Parsing wrapper for non PHP-5 servers. + */ function drupal_parse_json($v) { // PHP 5 only if (function_exists('json_decode')) { @@ -102,4 +146,103 @@ } } return $v; -} \ No newline at end of file +} + +/** + * Implementation of hook_form_alter(). + */ +function json_server_form_services_admin_settings_alter(&$form, &$form_state) { + $form['authentication']['#weight'] = -20; + $form['json_server'] = array( + '#type' => 'fieldset', + '#title' => t('JSONP Server'), + '#weight' => -10, + '#tree' => TRUE, + ); + $form['json_server']['json_server_jsonp'] = array( + '#type' => 'checkbox', + '#title' => t('Activate'), + '#description' => t('Enable JSONP Server. This will wrap the result as a callback, rather than just a JSON object.'), + '#default_value' => variable_get('json_server_jsonp', FALSE), + ); + $form['json_server']['json_server_jsonp_callback'] = array( + '#type' => 'textfield', + '#title' => t('JSONP callback'), + '#default_value' => variable_get('json_server_jsonp_callback', 'callback'), + '#description' => t('Which parameter should be used to find the specific callback name?'), + ); + $form['#submit'][] = 'json_server_form_services_admin_settings_alter_submit'; +} + + +/** + * Settings form; Submit handler + */ +function json_server_form_services_admin_settings_alter_submit($form, &$form_state) { + variable_set('json_server_jsonp', $form_state['values']['json_server']['json_server_jsonp']); + variable_set('json_server_jsonp_callback', $form_state['values']['json_server']['json_server_jsonp_callback']); +} + +/** + * Helper function to create json encoded strings. + */ +function json_server_encode_json($contents) { + // PHP 5+. + if (function_exists('json_encode')) { + $contents = json_encode($contents); + } + + // Support the old school. + else { + $contents = drupal_to_js($contents); + } + + // No gzip support. + // or it is JSONP. doesn't accept gzip data + if (variable_get('json_server_jsonp', FALSE) || headers_sent()) { + return $contents; + } + + // Check for gzip support. + else { + $accepted_encoding = $_SERVER['HTTP_ACCEPT_ENCODING']; + if (strpos($accepted_encoding, 'x-gzip') !== FALSE) { + $encoding = 'x-gzip'; + } elseif (strpos($accepted_encoding, 'gzip') !== FALSE) { + $encoding = 'gzip'; + } + + // No gzip supported. + else { + return $contents; + } + + // Add encoding with gzip. + header('Content-Encoding: '. $encoding); + $output = "\x1f\x8b\x08\x00\x00\x00\x00\x00"; + $size = strlen($contents); + $contents = gzcompress($contents, 9); + $contents = substr($contents, 0, $size); + + return $output . $contents; + } +} + +/** + * Alter function to allow other modules to change the data * + * This Changes the object in the cck fields to associative array + * + * @param unknown_type $data + */ +function json_server_json_data_node_save_alter($data) { + foreach ($data as $field => $content) { + $info = content_fields($field); + if (!$info) continue; + + foreach ($content as $delta => $val) { + $val = (array) $val; + $data->{$field}[$delta] = $val; + } + } +} +