PageRenderTime 55ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/ext/flashremoting/swx.php

https://github.com/elhakim22003/TypoFlash
PHP | 430 lines | 231 code | 61 blank | 138 comment | 32 complexity | bca661f17db203bd0a5a899e478b4220 MD5 | raw file
Possible License(s): GPL-2.0
  1. <?php
  2. /**
  3. * PHP implementation of SWX RPC.
  4. *
  5. * This script acts as the endpoint (gateway) for SWX RPC calls.
  6. * It returns a SWX SWF files
  7. *
  8. * @author Aral Balkan
  9. * @copyright (c) 2007 Aral Balkan
  10. * @link http://aralbalkan.com
  11. * @link http://swxformat.org
  12. *
  13. * Licensed under the Creative Commons GNU GPL License.
  14. *
  15. * This gateway handles incoming SWX requests. It instantiates
  16. * the requested service class and calls the requested method
  17. * on the service class instance, passing to it the data
  18. * argument (if any).
  19. *
  20. **/
  21. // Simple profiling
  22. function microtime_float()
  23. {
  24. list($usec, $sec) = explode(" ", microtime());
  25. return ((float)$usec + (float)$sec);
  26. }
  27. // Save start time
  28. $startTime = microtime_float();
  29. // Define E_STRICT if not defined so we don't get errors on PHP 4
  30. if (!defined('E_STRICT')) define('E_STRICT', 2048);
  31. define('LETTERS_AND_NUMBERS_ONLY', '/[a-zA-Z0-9_]/');
  32. $class = '';
  33. $method = '';
  34. $url = '';
  35. $data = 'array()';
  36. $debug = false;
  37. // Error handling
  38. function errorHandler($errorNum, $errorStr, $errorFile, $errorLine)
  39. {
  40. $errorMsg = "Error $errorNum: $errorStr in $errorFile, line $errorLine.";
  41. $GLOBALS['swxLastErrorMessage'] = $errorMsg;
  42. // Display the error message in the PHP error log
  43. error_log($errorMsg);
  44. $errorObj = array('error' => TRUE, 'code' => $errorNum, 'message' => $errorMsg);
  45. //if ($errorNum == E_ERROR || $errorNum == E_WARNING || $errorNum = E_USER_ERROR)
  46. // Error num check replaced by code from http://drupal.org/node/11772#comment-18383.
  47. // This stops PHP5 strict errors from failing a call (e.g., deprecated calls, etc.)
  48. //if (($errorNum & (E_ALL & E_STRICT) ^ (E_NOTICE & E_STRICT)) || $errorNum = E_USER_ERROR)
  49. if ($errorNum != E_STRICT && $errorNum != E_NOTICE)
  50. {
  51. // On errors and warnings, stop execution and return the
  52. // error message to the client. This is a far better
  53. // alternative to failing silently.
  54. returnError($errorObj);
  55. }
  56. }
  57. // Error handling (unfortunately has to be global to support PHP 4)
  58. set_error_handler('errorHandler');
  59. // Turn on error reporting
  60. error_reporting(E_ALL);
  61. // Load the configuration info
  62. include('swx_config.php');
  63. // Load and instantiate the SWX Assembler
  64. include('SwxAssembler.php');
  65. $swxAssembler = new SwxAssembler();
  66. // Global configuration information
  67. global $swx;
  68. $swx = array();
  69. // Change to the service folder from here on.
  70. // This works exactly like Amfphp to make sure that Amfphp and SWX
  71. // services are compatible.
  72. chdir($servicesPath);
  73. /**
  74. * Returns a SWX with the passed error message in the result object.
  75. *
  76. * @param (str) The error message to return to the client.
  77. *
  78. * @return void (exits)
  79. * @author Aral Balkan
  80. **/
  81. function returnError($errorObj)
  82. {
  83. global $swxAssembler, $debug;
  84. error_log($errorObj['message']);
  85. $swxAssembler->writeSwf($errorObj, $debug);
  86. exit();
  87. }
  88. /**
  89. * Reads parameters from the passed source.
  90. *
  91. * @param array Either $_GET or $_POST.
  92. * @return void
  93. * @author Aral Balkan
  94. **/
  95. function getParameters($source)
  96. {
  97. global $class, $method, $data, $debug, $swxAssembler, $isParameterObject, $url;
  98. // Debug mode?
  99. if (array_key_exists('debug', $source))
  100. {
  101. $debug = ($source['debug'] === 'true');
  102. }
  103. else
  104. {
  105. // If no debug parameter is passed, debug defaults to false.
  106. $debug = false;
  107. }
  108. // Were any arguments passed?
  109. if (isset($source['args'])) // if (array_key_exists('args', $source))
  110. {
  111. // error_log('[SWX] INFO Arguments: ' . $source['args']);
  112. $data = $source['args'];
  113. }
  114. // Get the class name
  115. if (isset($source['serviceClass'])) //if (array_key_exists('serviceClass', $source))
  116. {
  117. $class = $source['serviceClass'];
  118. }
  119. else
  120. {
  121. // Error: Service class argument is missing.
  122. trigger_error('The \'serviceClass\' argument is missing (no class name was supplied)', E_USER_ERROR);
  123. }
  124. // Check if service class is null or undefined
  125. if ($class === "null") trigger_error('The \'serviceClass\' argument is null.', E_USER_ERROR);
  126. if ($class === "undefined") trigger_error('The \'serviceClass\' argument is undefined.', E_USER_ERROR);
  127. // Get the method name
  128. if (isset($source['method'])) // if (array_key_exists('method', $source))
  129. {
  130. $method = $source['method'];
  131. }
  132. else
  133. {
  134. // Error: Method argument is missing.
  135. trigger_error('The \'method\' argument is missing (no method name was supplied)', E_USER_ERROR);
  136. }
  137. // Check if method is null or undefined
  138. if ($method === "null") trigger_error('The \'method\' argument is null.', E_USER_ERROR);
  139. if ($method === "undefined") trigger_error('The \'method\' argument is undefined.', E_USER_ERROR);
  140. // TODO: Implement as part of the new security
  141. // model in the next Beta.
  142. //
  143. // Get the url that we are being called from
  144. // (for cross-domain support)
  145. if (isset($source['url'])) //(array_key_exists('url', $source))
  146. {
  147. $url = urldecode($source['url']);
  148. // Firefox/Flash (at least, and tested only on a Mac), sends
  149. // file:/// (three slashses) in the URI and that fails the validation
  150. // so replacing that with two slashes instead.
  151. $url = str_replace('///', '//', $url);
  152. if (LOG_ALL) error_log('[SWX] INFO: SWX gateway called from '.$url);
  153. }
  154. else
  155. {
  156. error_log('[SWX] Warning: No referring URL received from Flash. Cross-domain will not be supported on this call regardless of allowDomain setting.');
  157. }
  158. }
  159. // Check if the className is supplied as a GET var. If so,
  160. // we'll use those. Using GET is useful for debugging.
  161. //if (isset($_GET['serviceClass'])) // (array_key_exists('serviceClass', $_GET))
  162. if ($_SERVER['REQUEST_METHOD'] === 'GET')
  163. {
  164. // GET
  165. //error_log('[SWX] INFO Using GET.');
  166. getParameters($_GET);
  167. }
  168. else
  169. {
  170. // POST
  171. //error_log('[SWX] INFO Using POST.');
  172. getParameters($_POST);
  173. }
  174. // Security: Check that only allowed characters are present in the URL.
  175. require_once('lib/Validate.php');
  176. $v = new Validate();
  177. /*
  178. $options = array
  179. (
  180. 'domain_check' => false,
  181. 'allow_schemes' => array
  182. (
  183. 'http', 'https', 'file'
  184. ),
  185. 'strict' => ''
  186. );
  187. */
  188. $urlValid = $v->uri($url);
  189. if ($urlValid != 1)
  190. {
  191. error_log('[SWX] Non-fatal error: URL is not valid. Cross-domain access will not work. ' . $url);
  192. }
  193. else
  194. {
  195. // URL is valid
  196. if (LOG_ALL) error_log('[SWX] INFO: The referring URL is valid.');
  197. }
  198. // Security: Check that only allowed characters are present
  199. // in the class and method names.
  200. //$classNameDisallowedCharacters = preg_replace(LETTERS_AND_NUMBERS_ONLY, '', $class);
  201. $methodNameDisallowedCharacters = preg_replace(LETTERS_AND_NUMBERS_ONLY, '', $method);
  202. //Borg removed this check as it disabled class dot path syntax
  203. /*if ($classNameDisallowedCharacters !== '')
  204. {
  205. // Error: Invalid class name.
  206. trigger_error("The supplied class name ($class) is invalid (it must only contain letters, numbers, and underscores)", E_USER_ERROR);
  207. } */
  208. if ($methodNameDisallowedCharacters !== '')
  209. {
  210. // Error: Invalid method name.
  211. trigger_error("The supplied method name ($method) is invalid (it must only contain letters, numbers, and underscores)", E_USER_ERROR);
  212. }
  213. // Load in the requested class
  214. //Borg added support for dot syntax and folder structure
  215. $classArr = explode('.',$class);
  216. if(count($classArr)>0){
  217. $class = array_pop($classArr);
  218. $classPath = implode('/',$classArr);
  219. $classPath .='/';
  220. }else{
  221. $classPath='';
  222. }
  223. $classToLoad = $servicesPath .$classPath. $class.'.php';
  224. if (is_file($classToLoad))
  225. {
  226. include($classToLoad);
  227. }
  228. else
  229. {
  230. // The requested class does not exist.
  231. trigger_error('Could not find a class named '.$classToLoad, E_USER_ERROR);
  232. }
  233. // Instantiate the requested service class and
  234. // call the requested method on it, capturing the return value.
  235. $instance = new $class();
  236. // Security: Check that user is not trying to call a private method
  237. if (substr(phpversion(), 0,1) == '4')
  238. {
  239. // PHP 4 check
  240. if (substr($method, 0, 1) === '_' || !method_exists($instance, $method))
  241. {
  242. // Error: The requested method either does not exist or is private (PHP 4).
  243. trigger_error("Could not find a public method in $class called $method(). (Using PHP 4 rules.)", E_USER_ERROR);
  244. }
  245. }
  246. else
  247. {
  248. // PHP 5 check
  249. $allowedMethods = get_class_methods($class);
  250. if (array_search($method, $allowedMethods) === false || substr($method, 0, 1) === '_')
  251. {
  252. // Error: The requested method either does not exist or is private (PHP 5).
  253. trigger_error("Could not find a public method in $class called $method(). (Using PHP 5 rules.)", E_USER_ERROR);
  254. }
  255. }
  256. // Strip slashes in data
  257. $dataAsPhp = stripslashes($data);
  258. // If the user did not pass an args array, treat it as
  259. // an empty args array. (Although this may be an error
  260. // on the client side, it may also be the user calling
  261. // a method that doesn't take arguments and we shouldn't
  262. // force the user to create an args parameter with an empty
  263. // array.)
  264. if ($dataAsPhp === "undefined") $dataAsPhp = "[]";
  265. // Massage special characters back (is there a better
  266. // way to do this?)
  267. $dataAsPhp = str_replace('\\t', '\t', $dataAsPhp);
  268. $dataAsPhp = str_replace('\\n', '\n', $dataAsPhp);
  269. $dataAsPhp = str_replace("\\'", "'", $dataAsPhp);
  270. // Check if there are any undefined values.
  271. if (strpos($dataAsPhp, 'undefined') !== FALSE)
  272. {
  273. // There is at least one undefined argument. This signals an error
  274. // on the Flash client (you should never pass undefined on purpose, use
  275. // null for optional arguments); signal the error to the user.
  276. $undefinedArgumentIndices = '';
  277. $numUndefinedArguments = 0;
  278. $arguments = explode(',', $dataAsPhp);
  279. $numArguments = count($arguments);
  280. for ($i = 0; $i < $numArguments; $i++)
  281. {
  282. $currentArgument = $arguments[$i];
  283. if (strpos($currentArgument, 'undefined'))
  284. {
  285. $undefinedArgumentIndices .= ', ' . $i;
  286. $numUndefinedArguments++;
  287. }
  288. }
  289. // Remove the initial comma and space.
  290. $undefinedArgumentIndices = substr($undefinedArgumentIndices, 2);
  291. // Make sure the error message is grammatically correct.
  292. $pluralization = $numUndefinedArguments > 1 ? 's' : '';
  293. $errorMsg = $numUndefinedArguments . ' undefined argument' . $pluralization . ' found at position' . $pluralization . ' ' . $undefinedArgumentIndices . ' for method '.$method.' in class '.$class.'.';
  294. trigger_error($errorMsg, E_USER_ERROR);
  295. }
  296. // Convert undefined and null to NULL
  297. //$dataAsPhp = str_replace('undefined', 'NULL', $dataAsPhp);
  298. $dataAsPhp = str_replace('null', 'NULL', $dataAsPhp);
  299. // Convert the passed JSON data to a PHP array structure.
  300. // TODO: Add error checking.
  301. // Profiling:
  302. if (LOG_ALL) $jsonStartTime = microtime_float();
  303. include_once('core/shared/util/JSON.php');
  304. $j = new Services_JSON();
  305. $dataAsPhp = $j->decode($dataAsPhp);
  306. if (LOG_ALL)
  307. {
  308. // Profiling:
  309. $jsonDuration = microtime_float() - $jsonStartTime;
  310. error_log("[SWX] PROFILING: JSON parser took $jsonDuration seconds to parse the arguments.");
  311. }
  312. // Profiling:
  313. // Service method
  314. if (LOG_ALL) $methodStartTime = microtime_float();
  315. // Call the method, passing the array's elements as individual elements.
  316. $result = call_user_func_array(array(&$instance, $method),$dataAsPhp);
  317. // Profiling:
  318. if (LOG_ALL)
  319. {
  320. $methodDuration = microtime_float() - $methodStartTime;
  321. error_log("[SWX] PROFILING: Method took $methodDuration seconds to return a result.");
  322. $duration = microtime_float() - $startTime;
  323. $swxGatewayOverhead = $duration - $jsonDuration - $methodDuration;
  324. error_log("[SWX] PROFILING: All other SWX gateway operations took $swxGatewayOverhead seconds.");
  325. // Debug:
  326. // error_log ("[SWX] INFO Method call result = $result");
  327. $swxAssemblerStartTime = microtime_float(); // Reset the timer.
  328. }
  329. // Create and write out the SWF.
  330. $swxAssembler->writeSwf($result, $debug, $compressionLevel, $url);
  331. if (LOG_ALL)
  332. {
  333. // Profiling:
  334. $swxCompilerDuration = microtime_float() - $swxAssemblerStartTime;
  335. $duration = microtime_float() - $startTime;
  336. // Status message.
  337. error_log("[SWX] PROFILING: SWF compiler took $swxCompilerDuration seconds to assemble the data SWF.");
  338. // Call profiling stats:
  339. $jsonPercentage = round($jsonDuration * 100 / $duration, 0);
  340. $swxAssemblerPercentage = round($swxCompilerDuration * 100 / $duration, 0);
  341. $methodPercentage = round($methodDuration * 100 / $duration, 0);
  342. $otherPercentage = 100 - $jsonPercentage - $swxAssemblerPercentage - $methodPercentage;
  343. error_log("[SWX] PROFILING: SWX call took $duration seconds in total, of which JSON decoding arguments: $jsonPercentage%, Service method: $methodPercentage%, SWX Data SWF assembly: $swxAssemblerPercentage%, Other: $otherPercentage%.");
  344. // Profiler:
  345. /*
  346. error_log("[SWX] PROFILER INFO FOLLOWS:");
  347. $profileInfo = __profiler__('get');
  348. foreach ($profileInfo as $functionName => $percentage)
  349. {
  350. $inSeconds = round($duration * $percentage / 100, 3);
  351. error_log("$functionName: $percentage% ($inSeconds seconds)");
  352. }
  353. */
  354. }
  355. ?>