| 1 |
<?php
|
| 2 |
// $Id: ac.inc,v 1.8 2009/06/17 22:48:15 ac Exp $
|
| 3 |
|
| 4 |
/**
|
| 5 |
* @file
|
| 6 |
* Ajax callback controller API.
|
| 7 |
* @author Tj Holowaychuk <tj@vision-media.ca>
|
| 8 |
* @maintainer ac <alex@spoon.com.au>
|
| 9 |
* @package ac
|
| 10 |
*/
|
| 11 |
|
| 12 |
/**
|
| 13 |
* Process the AC callback.
|
| 14 |
*
|
| 15 |
* @param string $module
|
| 16 |
*
|
| 17 |
* @param string $op
|
| 18 |
*/
|
| 19 |
function ac_process_request($module, $op) {
|
| 20 |
$func = "{$module}_js_{$op}";
|
| 21 |
|
| 22 |
// Ensure callback exists
|
| 23 |
if (!function_exists($func)){
|
| 24 |
watchdog('ac', 'Invalid callback function @function', array('@function' => $func), WATCHDOG_NOTICE);
|
| 25 |
die(t('Invalid callback.'));
|
| 26 |
}
|
| 27 |
|
| 28 |
// Validate token
|
| 29 |
if (!isset($_POST['token']) || !_ac_check_token($_POST['token'])){
|
| 30 |
watchdog('ac', 'Invalid token');
|
| 31 |
die(t('Callback failed.'));
|
| 32 |
}
|
| 33 |
|
| 34 |
// Build args from query string
|
| 35 |
$args = $_POST;
|
| 36 |
unset($args['q']);
|
| 37 |
|
| 38 |
// Execute callback
|
| 39 |
$response = _ac_get_default_response();
|
| 40 |
$response['_module'] = $module;
|
| 41 |
$response['_op'] = $op;
|
| 42 |
$func($response, $args);
|
| 43 |
|
| 44 |
// Allow modules to alter the response
|
| 45 |
drupal_alter('js_response', $response, $module, $op);
|
| 46 |
|
| 47 |
// Output
|
| 48 |
_ac_output($response);
|
| 49 |
}
|
| 50 |
|
| 51 |
/**
|
| 52 |
* Debug a variable.
|
| 53 |
*
|
| 54 |
* This function outputs PHP data to the Firebug console which
|
| 55 |
* is useful for quickly debugging XMLHttpRequests.
|
| 56 |
*
|
| 57 |
* @param mixed $var
|
| 58 |
*
|
| 59 |
* @param mixed ...
|
| 60 |
*/
|
| 61 |
function ac_debug($var) {
|
| 62 |
$args = func_get_args();
|
| 63 |
$js = "console.group('Debug');";
|
| 64 |
foreach((array) $args AS $arg){
|
| 65 |
$js .= 'console.log(' . drupal_to_js($arg) . ');';
|
| 66 |
}
|
| 67 |
$js .= "console.groupEnd('Debug');";
|
| 68 |
|
| 69 |
drupal_json(array('debug' => $js));
|
| 70 |
exit();
|
| 71 |
}
|
| 72 |
|
| 73 |
/**
|
| 74 |
* Build callback output.
|
| 75 |
*
|
| 76 |
* @param array $response
|
| 77 |
*
|
| 78 |
* @see ac_process_request()
|
| 79 |
*/
|
| 80 |
function _ac_output($response) {
|
| 81 |
$output = array();
|
| 82 |
|
| 83 |
// Assign error message when an error has occurred
|
| 84 |
if ($response['status'] == AC_STATUS_ERROR){
|
| 85 |
if (empty($response['message'])){
|
| 86 |
$response['message'] = AC_STATUS_ERROR_MESSAGE;
|
| 87 |
}
|
| 88 |
}
|
| 89 |
|
| 90 |
// Add response to output
|
| 91 |
// @todo remove arbitrary members
|
| 92 |
$output = $response;
|
| 93 |
|
| 94 |
// Format
|
| 95 |
// Currently only supporting JSON
|
| 96 |
$json = drupal_to_js($output);
|
| 97 |
drupal_set_header('Content-Type: text/javascript; charset=utf-8');
|
| 98 |
|
| 99 |
// Gzip output
|
| 100 |
if (AC_ENCODING_MAY_COMPRESS && $_SERVER['HTTP_ACCEPT_ENCODING'] == 'gzip,deflate'){
|
| 101 |
if ($response['encoding'] == AC_ENCODING_GZIP || ($response['encoding'] == AC_ENCODING_AUTO && _ac_check_length($json))){
|
| 102 |
if (function_exists('gzencode')){
|
| 103 |
drupal_set_header('Content-Encoding: gzip');
|
| 104 |
$json = gzencode($json);
|
| 105 |
}
|
| 106 |
}
|
| 107 |
}
|
| 108 |
|
| 109 |
// Set headers passed
|
| 110 |
foreach((array) $response['headers'] AS $header){
|
| 111 |
drupal_set_header($header);
|
| 112 |
}
|
| 113 |
|
| 114 |
// Output content
|
| 115 |
drupal_set_header('Content-Length: ' . strlen($json));
|
| 116 |
echo $json;
|
| 117 |
exit();
|
| 118 |
}
|
| 119 |
|
| 120 |
/**
|
| 121 |
* Validate the AC token passed.
|
| 122 |
*
|
| 123 |
* @param string $token
|
| 124 |
*
|
| 125 |
* @return bool
|
| 126 |
*
|
| 127 |
* @todo use drupal_valid_token().
|
| 128 |
*/
|
| 129 |
function _ac_check_token($token){
|
| 130 |
if (isset($_SESSION['ac_token']) && $_SESSION['ac_token'] == $token){
|
| 131 |
return TRUE;
|
| 132 |
}
|
| 133 |
|
| 134 |
return FALSE;
|
| 135 |
}
|
| 136 |
|
| 137 |
/**
|
| 138 |
* Validate weither or not output should be
|
| 139 |
* compressed based on the length of output.
|
| 140 |
*
|
| 141 |
* @param string $string
|
| 142 |
*
|
| 143 |
* @return bool
|
| 144 |
*/
|
| 145 |
function _ac_check_length($string){
|
| 146 |
if (strlen($string) >= AC_ENCODING_AUTO_THRESHOLD){
|
| 147 |
return TRUE;
|
| 148 |
}
|
| 149 |
|
| 150 |
return FALSE;
|
| 151 |
}
|
| 152 |
|
| 153 |
/**
|
| 154 |
* Get default response structure.
|
| 155 |
*
|
| 156 |
* @return array
|
| 157 |
*/
|
| 158 |
function _ac_get_default_response() {
|
| 159 |
// @todo allow usage of message_func = 'append' etc
|
| 160 |
// @todo add optional lock_message_duration
|
| 161 |
// @todo add optional lock_message_wrapper
|
| 162 |
// @todo add optional lock_message_func
|
| 163 |
// @todo add specific classes to all of these messages for overrides specific to AC
|
| 164 |
return array(
|
| 165 |
// Request status
|
| 166 |
'status' => AC_STATUS_OK,
|
| 167 |
// Message wrapped with t().
|
| 168 |
// This member is context sensative and will display an error
|
| 169 |
// when status is AC_STATUS_ERROR. When no error message is supplied
|
| 170 |
// variable_get('ac_error_message') is used.
|
| 171 |
'message' => '',
|
| 172 |
// CSS Selector used to place messages
|
| 173 |
'message_wrapper' => '#ac-messages',
|
| 174 |
// Message display duration in milliseconds
|
| 175 |
'message_duration' => 3000,
|
| 176 |
// Message positions allow you to choose where to display the message(s)
|
| 177 |
// relative to the message_wrapper using jQuery traversal methods.
|
| 178 |
// Ex: '.parent().after(message)' becomes evaluated as '$(wrapper).parent().after(message);'
|
| 179 |
'message_position' => NULL,
|
| 180 |
// Class(es) for the message
|
| 181 |
'message_class' => '',
|
| 182 |
// Additional output, markup, array, object, etc
|
| 183 |
'output' => NULL,
|
| 184 |
// Output encoding such as gzip or no plain-text
|
| 185 |
'encoding' => AC_ENCODING_AUTO,
|
| 186 |
// Output format. Currently supports JSON only, if you
|
| 187 |
// are in need of elaborate output formats view the server module
|
| 188 |
'format' => AC_OUTPUT_JSON,
|
| 189 |
// Lock request for a set duration of time in seconds. This optional member prevents
|
| 190 |
// users from arbitrarily (or accidentally) issueing the same request several times.
|
| 191 |
// Note that this will ONLY work when using AC.checkResponse().
|
| 192 |
'lock' => 0,
|
| 193 |
// Optional lock message which is displayed when the user IS locked from a specific
|
| 194 |
// request. Currently 'message_wrapper' and 'message_duration' are used just like the other mesages.
|
| 195 |
'lock_message' => '',
|
| 196 |
// Additional response headers.
|
| 197 |
'headers' => array(),
|
| 198 |
);
|
| 199 |
}
|
| 200 |
|
| 201 |
|