y_php.inc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525
  1. /**--------------------------------------------------------------------------**\
  2. =================================
  3. y_php - PHP synchronisation.
  4. =================================
  5. Description:
  6. Sends and receives data from a PHP server with shmop installed.
  7. Legal:
  8. Version: MPL 1.1
  9. The contents of this file are subject to the Mozilla Public License Version
  10. 1.1 (the "License"); you may not use this file except in compliance with
  11. the License. You may obtain a copy of the License at
  12. http://www.mozilla.org/MPL/
  13. Software distributed under the License is distributed on an "AS IS" basis,
  14. WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
  15. for the specific language governing rights and limitations under the
  16. License.
  17. The Original Code is the YSI utils include.
  18. The Initial Developer of the Original Code is Alex "Y_Less" Cole.
  19. Portions created by the Initial Developer are Copyright (C) 2011
  20. the Initial Developer. All Rights Reserved.
  21. Contributors:
  22. ZeeX, koolk, JoeBullet/Google63, g_aSlice/Slice
  23. Thanks:
  24. JoeBullet/Google63 - Handy arbitrary ASM jump code using SCTRL.
  25. ZeeX - Very productive conversations.
  26. koolk - IsPlayerinAreaEx code.
  27. TheAlpha - Danish translation.
  28. breadfish - German translation.
  29. Fireburn - Dutch translation.
  30. yom - French translation.
  31. 50p - Polish translation.
  32. Zamaroht - Spanish translation.
  33. Dracoblue, sintax, mabako, Xtreme, other coders - Producing other modes
  34. for me to strive to better.
  35. Pixels^ - Running XScripters where the idea was born.
  36. Matite - Pestering me to release it and using it.
  37. Very special thanks to:
  38. Thiadmer - PAWN, whose limits continue to amaze me!
  39. Kye/Kalcor - SA:MP.
  40. SA:MP Team past, present and future - SA:MP.
  41. Version:
  42. 0.1
  43. Changelog:
  44. 25/02/12:
  45. First version.
  46. Functions:
  47. Stock:
  48. -
  49. Inline:
  50. -
  51. Variables:
  52. Global:
  53. -
  54. </remarks>
  55. \**--------------------------------------------------------------------------**/
  56. #include <a_http>
  57. #include "y_utils"
  58. #include "internal\y_funcinc"
  59. #include "y_debug"
  60. #include "y_timers"
  61. #include "y_master"
  62. #include "y_hooks"
  63. #if !defined PHP_RECEIVE || !defined PHP_SEND
  64. #error You must define PHP_RECEIVE and PHP_SEND before including y_php.
  65. #endif
  66. #define PHP_HEADER_LENGTH (3)
  67. static stock
  68. YSI_g_sID = 0,
  69. //YSI_g_sLen,
  70. YSI_g_sIndex = PHP_HEADER_LENGTH,
  71. YSI_g_sBuffer[2048] = "DR=";
  72. /*
  73. native PHP_SendString(string:name[], string:value[], bool:priority = false);
  74. native PHP_SendFloat(string:name[], Float:value, bool:priority = false);
  75. native PHP_SendBool(string:name[], bool:value, bool:priority = false);
  76. native PHP_SendInt(string:name[], value, bool:priority = false);
  77. */
  78. enum
  79. {
  80. e_PHP_SEND_TYPE_STRING,
  81. e_PHP_SEND_TYPE_FLOAT,
  82. e_PHP_SEND_TYPE_BOOL,
  83. e_PHP_SEND_TYPE_INT
  84. }
  85. //foreign _PHP_Send(string:name[], string:value[], bool:priority, type);
  86. forward _PHP_Result(index, response, data[]);
  87. forward _PHP_Ignore(index, response, data[]);
  88. stock PHP_SendString(string:name[], string:value[], bool:priority = false)
  89. {
  90. if (isnull(value))
  91. {
  92. return _PHP_Send(name, NULL, priority, e_PHP_SEND_TYPE_STRING);
  93. }
  94. else
  95. {
  96. return _PHP_Send(name, value, priority, e_PHP_SEND_TYPE_STRING);
  97. }
  98. }
  99. stock PHP_SendFloat(string:name[], Float:value, bool:priority = false)
  100. {
  101. static
  102. sStr[6];
  103. PHP_EncodeFloat(_:value, sStr);
  104. return _PHP_Send(name, sStr, priority, e_PHP_SEND_TYPE_FLOAT);
  105. }
  106. stock PHP_SendBool(string:name[], bool:value, bool:priority = false)
  107. {
  108. if (value)
  109. {
  110. return _PHP_Send(name, "1", priority, e_PHP_SEND_TYPE_BOOL);
  111. }
  112. else
  113. {
  114. return _PHP_Send(name, "0", priority, e_PHP_SEND_TYPE_BOOL);
  115. }
  116. }
  117. stock PHP_SendInt(string:name[], value, bool:priority = false)
  118. {
  119. static
  120. sStr[6];
  121. PHP_EncodeInt(value, sStr);
  122. return _PHP_Send(name, sStr, priority, e_PHP_SEND_TYPE_INT);
  123. }
  124. static stock _PHP_Send(string:name[], string:value[], bool:priority, type)
  125. {
  126. new
  127. nlen = strlen(name);
  128. // Only loops twice max in reality.
  129. for ( ; ; )
  130. {
  131. switch (type)
  132. {
  133. case e_PHP_SEND_TYPE_STRING:
  134. {
  135. new
  136. vlen = strlen(value);
  137. if (vlen + nlen + 7 + YSI_g_sIndex < sizeof (YSI_g_sBuffer))
  138. {
  139. static
  140. sStr[6];
  141. PHP_EncodeInt(vlen, sStr);
  142. format(YSI_g_sBuffer[YSI_g_sIndex], sizeof (YSI_g_sBuffer), "%c%s%s%s%c", nlen | 0x80, name, sStr, value, 255);
  143. YSI_g_sIndex += vlen + nlen + 7;
  144. if (priority)
  145. {
  146. _PHP_ForceSend();
  147. }
  148. return 1;
  149. }
  150. }
  151. case e_PHP_SEND_TYPE_FLOAT, e_PHP_SEND_TYPE_INT:
  152. {
  153. if (nlen + 7 + YSI_g_sIndex < sizeof (YSI_g_sBuffer))
  154. {
  155. format(YSI_g_sBuffer[YSI_g_sIndex], sizeof (YSI_g_sBuffer), "%c%s%s%c", nlen | 0x80, name, value, 255);
  156. YSI_g_sIndex += nlen + 7;
  157. if (priority)
  158. {
  159. _PHP_ForceSend();
  160. }
  161. return 1;
  162. }
  163. }
  164. case e_PHP_SEND_TYPE_BOOL:
  165. {
  166. if (nlen + 2 + YSI_g_sIndex < sizeof (YSI_g_sBuffer))
  167. {
  168. format(YSI_g_sBuffer[YSI_g_sIndex], sizeof (YSI_g_sBuffer), "%c%s%c", nlen | 0x80, name, value[0]);
  169. YSI_g_sIndex += nlen + 2;
  170. if (priority)
  171. {
  172. _PHP_ForceSend();
  173. }
  174. return 1;
  175. }
  176. }
  177. }
  178. // Not enough space in the buffer. Send the existing data, reset
  179. // "YSI_g_sIndex", and try again (just once).
  180. if (YSI_g_sIndex > PHP_HEADER_LENGTH)
  181. {
  182. _PHP_ForceSend();
  183. }
  184. else
  185. {
  186. break;
  187. }
  188. }
  189. return 0;
  190. }
  191. task _PHP_ForceSend[5000]()
  192. {
  193. // This is run in all scripts, not just the master one, because there is no
  194. // "mtask". In retrospect, that seems like an oversight.
  195. if (YSI_g_sIndex > PHP_HEADER_LENGTH)
  196. {
  197. // Send the data.
  198. HTTP(0, HTTP_POST, PHP_SEND, YSI_g_sBuffer, "_PHP_Ignore");
  199. YSI_g_sIndex = PHP_HEADER_LENGTH;
  200. // I don't think this is actually REQUIRED, but does no harm.
  201. YSI_g_sBuffer[PHP_HEADER_LENGTH] = '\0';
  202. }
  203. }
  204. static stock PHP_EncodeInt(value, dest[])
  205. {
  206. dest[0] = (value >> 25 & 0x7F | 0x80);
  207. dest[1] = (value >> 18 & 0x7F | 0x80);
  208. dest[2] = (value >> 11 & 0x7F | 0x80);
  209. dest[3] = (value >> 4 & 0x7F | 0x80);
  210. dest[4] = (value & 0x0F | 0x80);
  211. }
  212. static stock PHP_EncodeFloat(value, dest[])
  213. {
  214. dest[0] = (value >> 25 & 0x7F | 0x80);
  215. dest[1] = (value >> 18 & 0x7F | 0x80);
  216. dest[2] = (value >> 11 & 0x7F | 0x80);
  217. dest[3] = (value >> 4 & 0x7F | 0x80);
  218. // This is the only difference from "PHP_EncodeInt" (0x80 vs 0xC0).
  219. dest[4] = (value & 0x0F | 0xC0);
  220. }
  221. mhook OnScriptInit()
  222. {
  223. if (!strcmp(PHP_RECEIVE, "http://", true, 7))
  224. {
  225. P:E("PHP_RECEIVE should exclude \"http://\".");
  226. }
  227. P:I("Starting PHP Connection...");
  228. P:I("Note that messages may take a few seconds to get going.");
  229. //YSI_g_sLen = strlen(PHP_RECEIVE) + 4;
  230. //SetTimer("_PHP_FireOne", 50, 0);
  231. // Send '0' only once at server start to reset PHP.
  232. HTTP(0, HTTP_HEAD, PHP_RECEIVE "?ID=0", "", "_PHP_Result");
  233. //new TODO;
  234. defer _PHP_FireOne[500](0, 0);
  235. defer _PHP_FireOne[5500](0, 0);
  236. //SetTimer("_PHP_FireOne", 500, 0);
  237. //SetTimer("_PHP_FireOne", 5500, 0);
  238. //PHP_FireOne();
  239. //PHP_FireOne();
  240. //PHP_FireOne();
  241. return 1;
  242. }
  243. timer _PHP_FireOne[10](res, to)
  244. {
  245. static
  246. sAddr[64]; // = PHP_RECEIVE "?ID=?????&RE=???????????";
  247. YSI_g_sID = (YSI_g_sID + 1) & 0xFFFF;
  248. if (YSI_g_sID == 0) YSI_g_sID = 1;
  249. //valstr(sAddr[YSI_g_sLen], YSI_g_sID);
  250. format(sAddr, sizeof (sAddr), PHP_RECEIVE "?ID=%d&RE=%d&TO=%d", YSI_g_sID, res, to);
  251. P:1("_PHP_FireOne request: %s: ", sAddr);
  252. HTTP(YSI_g_sID, HTTP_GET, sAddr, "", "_PHP_Result");
  253. }
  254. static stock PHP_GetNum32(str[])
  255. {
  256. return ((str[0] & ~0x80) << 25) | ((str[1] & ~0x80) << 18) | ((str[2] & ~0x80) << 11) | ((str[3] & ~0x80) << 4) | (str[4] & ~0xF0);
  257. }
  258. static stock PHP_GetNum8(str[])
  259. {
  260. return str[0] & ~0x80;
  261. }
  262. static stock PHP_GetNum6(str[])
  263. {
  264. return str[0] & ~0x40;
  265. }
  266. static stock bool:PHP_GetBool(str[])
  267. {
  268. return str[0] == '1';
  269. }
  270. public _PHP_Ignore(index, response, data[])
  271. {
  272. P:1("_PHP_Ignore: %i, %i, %s", index, response, data);
  273. return 0;
  274. }
  275. public _PHP_Result(index, response, data[])
  276. {
  277. P:1("_PHP_Result called: %d %d %s", index, response, data);
  278. if (response == 200)
  279. {
  280. // Fire a replacement.
  281. //PHP_FireOne();
  282. if (index)
  283. {
  284. new
  285. res = 0;
  286. switch (data[0])
  287. {
  288. case '1':
  289. {
  290. //P:I("PHP: Got response.");
  291. // Now parse the data.
  292. //printf(data);
  293. static
  294. sFunc[32],
  295. bool:sTrue = true,
  296. bool:sFalse = false;
  297. for (new i = 1, len = strlen(data); i < len; )
  298. {
  299. //new
  300. // flen = PHP_GetNum8(data[i]) + i + 1;
  301. //data[flen] = '\0';
  302. //format(sFunc, sizeof (sFunc), "%s@yP_", data[i + 1]);
  303. //i = flen;
  304. //printf("%d %d", i, data[i]);
  305. new
  306. flen = PHP_GetNum8(data[i++]);
  307. //printf("%d", flen);
  308. //data[flen] = '\0';
  309. format(sFunc, sizeof (sFunc), "%.*s@yP_", flen, data[i]);
  310. //printf("%s", sFunc);
  311. i += flen;
  312. //printf("%d", data[i]);
  313. if (data[i] & 0x80)
  314. {
  315. flen = PHP_GetNum32(data[i]);
  316. i += 5;
  317. if (data[i] == 255)
  318. {
  319. P:5("_PHP_Result: Got number.");
  320. // Number.
  321. /*if (data[i - 1] & 0x40)
  322. {
  323. CallRemoteFunction(sFunc, "f", flen);
  324. }
  325. else
  326. {
  327. CallRemoteFunction(sFunc, "i", flen);
  328. }*/
  329. CallRemoteFunction(sFunc, "i", flen);
  330. ++i;
  331. }
  332. else
  333. {
  334. P:5("_PHP_Result: Got string.");
  335. // String.
  336. flen += i;
  337. data[flen] = '\0';
  338. CallRemoteFunction(sFunc, "s", data[i]);
  339. i = flen + 1;
  340. }
  341. }
  342. else if (data[i] & 0x40)
  343. {
  344. sFunc[flen] = '_';
  345. sFunc[flen + 3] = '@';
  346. // Function call.
  347. new
  348. params = PHP_GetNum6(data[i]),
  349. n = params * 4 + 8,
  350. heap = 0;
  351. static
  352. sFormat[64];
  353. ++i;
  354. sFormat[params] = '\0';
  355. P:5("_PHP_Result: Got function %s.", sFunc);
  356. while (params--)
  357. {
  358. if (data[i] & 0x80)
  359. {
  360. flen = PHP_GetNum32(data[i]);
  361. i += 5;
  362. if (data[i] == 255)
  363. {
  364. P:5("_PHP_Result: Got number parameter (%d).", flen);
  365. sFormat[params] = 'i';
  366. // Number.
  367. #emit LOAD.S.pri flen
  368. #emit HEAP 4
  369. #emit STOR.I
  370. #emit PUSH.alt
  371. heap += 4;
  372. ++i;
  373. }
  374. else
  375. {
  376. sFormat[params] = 's';
  377. // String
  378. flen += i;
  379. data[flen] = '\0';
  380. P:5("_PHP_Result: Got string parameter (%d: %s).", flen, data[i]);
  381. #emit LOAD.S.pri i
  382. #emit LOAD.S.alt data // Not ADDR.alt.
  383. #emit IDXADDR
  384. #emit PUSH.pri
  385. //CallRemoteFunction(sFunc, "s", data[i]);
  386. i = flen + 1;
  387. }
  388. }
  389. else if (data[i] == '1')
  390. {
  391. P:5("_PHP_Result: Got true parameter.");
  392. sFormat[params] = 'i';
  393. #emit PUSH.C sTrue
  394. ++i;
  395. }
  396. else
  397. {
  398. P:5("_PHP_Result: Got false parameter.");
  399. sFormat[params] = 'i';
  400. #emit PUSH.C sFalse
  401. ++i;
  402. }
  403. }
  404. P:5("_PHP_Result: Do function call.");
  405. // Push the static parameters and call the function.
  406. #emit PUSH.C sFormat
  407. #emit PUSH.C sFunc
  408. #emit PUSH.S n
  409. #emit SYSREQ.C CallRemoteFunction
  410. //n += 4;
  411. //#emit POP.pri
  412. // Save the return.
  413. #emit STOR.S.pri res
  414. // Clear the stack, including the return.
  415. #emit LCTRL 4
  416. #emit LOAD.S.alt n
  417. #emit ADD
  418. #emit ADD.C 4
  419. #emit SCTRL 4
  420. // Clear the heap.
  421. #emit LCTRL 2
  422. #emit LOAD.S.alt heap
  423. #emit SUB
  424. #emit SCTRL 2
  425. // Have a return.
  426. }
  427. else if (data[i] == '1')
  428. {
  429. P:5("_PHP_Result: Got true.");
  430. CallRemoteFunction(sFunc, "i", sTrue);
  431. ++i;
  432. }
  433. else
  434. {
  435. P:5("_PHP_Result: Got false.");
  436. CallRemoteFunction(sFunc, "i", sFalse);
  437. ++i;
  438. }
  439. }
  440. }
  441. case '\0':
  442. {
  443. P:E("PHP: Empty response.");
  444. }
  445. default:
  446. {
  447. // Error or unknown.
  448. switch (data[1])
  449. {
  450. case '0':
  451. {
  452. P:E("PHP: ID out of bounds.");
  453. }
  454. case '1':
  455. {
  456. P:E("PHP: Could not open shared memory.");
  457. }
  458. case '2':
  459. {
  460. //P:E("PHP: ID out of bounds.");
  461. // Not an error!
  462. }
  463. case '3':
  464. {
  465. P:F("PHP: Server does not support Shared Memory Extensions (shmop).");
  466. // Fatal error (one of only two ever)!
  467. return;
  468. }
  469. default:
  470. {
  471. P:E("PHP: Unknown error: %s.", data[1]);
  472. }
  473. }
  474. }
  475. }
  476. //new TODO;
  477. defer _PHP_FireOne(res, index);
  478. }
  479. }
  480. else
  481. {
  482. defer _PHP_FireOne[5000](0, 0);
  483. }
  484. }
  485. #define phpdata%0(%1) %0@yP_(%1);public%0@yP_(%1)
  486. #define phpfunc%0(%1) %0_yP@(%1);public%0_yP@(%1)
  487. #include "internal\y_grouprevert"