1
0

y_php.inc 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524
  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. \*----------------------------------------------------------------------------*/
  55. #include <a_http>
  56. #include "y_utils"
  57. #include "internal\y_funcinc"
  58. #include "y_debug"
  59. #include "y_timers"
  60. #include "y_master"
  61. #include "y_hooks"
  62. #if !defined PHP_RECEIVE || !defined PHP_SEND
  63. #error You must define PHP_RECEIVE and PHP_SEND before including y_php.
  64. #endif
  65. #define PHP_HEADER_LENGTH (3)
  66. static stock
  67. YSI_g_sID = 0,
  68. //YSI_g_sLen,
  69. YSI_g_sIndex = PHP_HEADER_LENGTH,
  70. YSI_g_sBuffer[2048] = "DR=";
  71. /*
  72. native PHP_SendString(string:name[], string:value[], bool:priority = false);
  73. native PHP_SendFloat(string:name[], Float:value, bool:priority = false);
  74. native PHP_SendBool(string:name[], bool:value, bool:priority = false);
  75. native PHP_SendInt(string:name[], value, bool:priority = false);
  76. */
  77. enum
  78. {
  79. e_PHP_SEND_TYPE_STRING,
  80. e_PHP_SEND_TYPE_FLOAT,
  81. e_PHP_SEND_TYPE_BOOL,
  82. e_PHP_SEND_TYPE_INT
  83. }
  84. //foreign _PHP_Send(string:name[], string:value[], bool:priority, type);
  85. forward _PHP_Result(index, response, data[]);
  86. forward _PHP_Ignore(index, response, data[]);
  87. stock PHP_SendString(string:name[], string:value[], bool:priority = false)
  88. {
  89. if (isnull(value))
  90. {
  91. return _PHP_Send(name, NULL, priority, e_PHP_SEND_TYPE_STRING);
  92. }
  93. else
  94. {
  95. return _PHP_Send(name, value, priority, e_PHP_SEND_TYPE_STRING);
  96. }
  97. }
  98. stock PHP_SendFloat(string:name[], Float:value, bool:priority = false)
  99. {
  100. static
  101. sStr[6];
  102. PHP_EncodeFloat(_:value, sStr);
  103. return _PHP_Send(name, sStr, priority, e_PHP_SEND_TYPE_FLOAT);
  104. }
  105. stock PHP_SendBool(string:name[], bool:value, bool:priority = false)
  106. {
  107. if (value)
  108. {
  109. return _PHP_Send(name, "1", priority, e_PHP_SEND_TYPE_BOOL);
  110. }
  111. else
  112. {
  113. return _PHP_Send(name, "0", priority, e_PHP_SEND_TYPE_BOOL);
  114. }
  115. }
  116. stock PHP_SendInt(string:name[], value, bool:priority = false)
  117. {
  118. static
  119. sStr[6];
  120. PHP_EncodeInt(value, sStr);
  121. return _PHP_Send(name, sStr, priority, e_PHP_SEND_TYPE_INT);
  122. }
  123. static stock _PHP_Send(string:name[], string:value[], bool:priority, type)
  124. {
  125. new
  126. nlen = strlen(name);
  127. // Only loops twice max in reality.
  128. for ( ; ; )
  129. {
  130. switch (type)
  131. {
  132. case e_PHP_SEND_TYPE_STRING:
  133. {
  134. new
  135. vlen = strlen(value);
  136. if (vlen + nlen + 7 + YSI_g_sIndex < sizeof (YSI_g_sBuffer))
  137. {
  138. static
  139. sStr[6];
  140. PHP_EncodeInt(vlen, sStr);
  141. format(YSI_g_sBuffer[YSI_g_sIndex], sizeof (YSI_g_sBuffer), "%c%s%s%s%c", nlen | 0x80, name, sStr, value, 255);
  142. YSI_g_sIndex += vlen + nlen + 7;
  143. if (priority)
  144. {
  145. _PHP_ForceSend();
  146. }
  147. return 1;
  148. }
  149. }
  150. case e_PHP_SEND_TYPE_FLOAT, e_PHP_SEND_TYPE_INT:
  151. {
  152. if (nlen + 7 + YSI_g_sIndex < sizeof (YSI_g_sBuffer))
  153. {
  154. format(YSI_g_sBuffer[YSI_g_sIndex], sizeof (YSI_g_sBuffer), "%c%s%s%c", nlen | 0x80, name, value, 255);
  155. YSI_g_sIndex += nlen + 7;
  156. if (priority)
  157. {
  158. _PHP_ForceSend();
  159. }
  160. return 1;
  161. }
  162. }
  163. case e_PHP_SEND_TYPE_BOOL:
  164. {
  165. if (nlen + 2 + YSI_g_sIndex < sizeof (YSI_g_sBuffer))
  166. {
  167. format(YSI_g_sBuffer[YSI_g_sIndex], sizeof (YSI_g_sBuffer), "%c%s%c", nlen | 0x80, name, value[0]);
  168. YSI_g_sIndex += nlen + 2;
  169. if (priority)
  170. {
  171. _PHP_ForceSend();
  172. }
  173. return 1;
  174. }
  175. }
  176. }
  177. // Not enough space in the buffer. Send the existing data, reset
  178. // "YSI_g_sIndex", and try again (just once).
  179. if (YSI_g_sIndex > PHP_HEADER_LENGTH)
  180. {
  181. _PHP_ForceSend();
  182. }
  183. else
  184. {
  185. break;
  186. }
  187. }
  188. return 0;
  189. }
  190. task _PHP_ForceSend[5000]()
  191. {
  192. // This is run in all scripts, not just the master one, because there is no
  193. // "mtask". In retrospect, that seems like an oversight.
  194. if (YSI_g_sIndex > PHP_HEADER_LENGTH)
  195. {
  196. // Send the data.
  197. HTTP(0, HTTP_POST, PHP_SEND, YSI_g_sBuffer, "_PHP_Ignore");
  198. YSI_g_sIndex = PHP_HEADER_LENGTH;
  199. // I don't think this is actually REQUIRED, but does no harm.
  200. YSI_g_sBuffer[PHP_HEADER_LENGTH] = '\0';
  201. }
  202. }
  203. static stock PHP_EncodeInt(value, dest[])
  204. {
  205. dest[0] = (value >> 25 & 0x7F | 0x80);
  206. dest[1] = (value >> 18 & 0x7F | 0x80);
  207. dest[2] = (value >> 11 & 0x7F | 0x80);
  208. dest[3] = (value >> 4 & 0x7F | 0x80);
  209. dest[4] = (value & 0x0F | 0x80);
  210. }
  211. static stock PHP_EncodeFloat(value, dest[])
  212. {
  213. dest[0] = (value >> 25 & 0x7F | 0x80);
  214. dest[1] = (value >> 18 & 0x7F | 0x80);
  215. dest[2] = (value >> 11 & 0x7F | 0x80);
  216. dest[3] = (value >> 4 & 0x7F | 0x80);
  217. // This is the only difference from "PHP_EncodeInt" (0x80 vs 0xC0).
  218. dest[4] = (value & 0x0F | 0xC0);
  219. }
  220. mhook OnScriptInit()
  221. {
  222. if (!strcmp(PHP_RECEIVE, "http://", true, 7))
  223. {
  224. P:E("PHP_RECEIVE should exclude \"http://\".");
  225. }
  226. P:I("Starting PHP Connection...");
  227. P:I("Note that messages may take a few seconds to get going.");
  228. //YSI_g_sLen = strlen(PHP_RECEIVE) + 4;
  229. //SetTimer("_PHP_FireOne", 50, 0);
  230. // Send '0' only once at server start to reset PHP.
  231. HTTP(0, HTTP_HEAD, PHP_RECEIVE "?ID=0", "", "_PHP_Result");
  232. //new TODO;
  233. defer _PHP_FireOne[500](0, 0);
  234. defer _PHP_FireOne[5500](0, 0);
  235. //SetTimer("_PHP_FireOne", 500, 0);
  236. //SetTimer("_PHP_FireOne", 5500, 0);
  237. //PHP_FireOne();
  238. //PHP_FireOne();
  239. //PHP_FireOne();
  240. return 1;
  241. }
  242. timer _PHP_FireOne[10](res, to)
  243. {
  244. static
  245. sAddr[64]; // = PHP_RECEIVE "?ID=?????&RE=???????????";
  246. YSI_g_sID = (YSI_g_sID + 1) & 0xFFFF;
  247. if (YSI_g_sID == 0) YSI_g_sID = 1;
  248. //valstr(sAddr[YSI_g_sLen], YSI_g_sID);
  249. format(sAddr, sizeof (sAddr), PHP_RECEIVE "?ID=%d&RE=%d&TO=%d", YSI_g_sID, res, to);
  250. P:1("_PHP_FireOne request: %s: ", sAddr);
  251. HTTP(YSI_g_sID, HTTP_GET, sAddr, "", "_PHP_Result");
  252. }
  253. static stock PHP_GetNum32(str[])
  254. {
  255. return ((str[0] & ~0x80) << 25) | ((str[1] & ~0x80) << 18) | ((str[2] & ~0x80) << 11) | ((str[3] & ~0x80) << 4) | (str[4] & ~0xF0);
  256. }
  257. static stock PHP_GetNum8(str[])
  258. {
  259. return str[0] & ~0x80;
  260. }
  261. static stock PHP_GetNum6(str[])
  262. {
  263. return str[0] & ~0x40;
  264. }
  265. static stock bool:PHP_GetBool(str[])
  266. {
  267. return str[0] == '1';
  268. }
  269. public _PHP_Ignore(index, response, data[])
  270. {
  271. P:1("_PHP_Ignore: %i, %i, %s", index, response, data);
  272. return 0;
  273. }
  274. public _PHP_Result(index, response, data[])
  275. {
  276. P:1("_PHP_Result called: %d %d %s", index, response, data);
  277. if (response == 200)
  278. {
  279. // Fire a replacement.
  280. //PHP_FireOne();
  281. if (index)
  282. {
  283. new
  284. res = 0;
  285. switch (data[0])
  286. {
  287. case '1':
  288. {
  289. //P:I("PHP: Got response.");
  290. // Now parse the data.
  291. //printf(data);
  292. static
  293. sFunc[32],
  294. bool:sTrue = true,
  295. bool:sFalse = false;
  296. for (new i = 1, len = strlen(data); i < len; )
  297. {
  298. //new
  299. // flen = PHP_GetNum8(data[i]) + i + 1;
  300. //data[flen] = '\0';
  301. //format(sFunc, sizeof (sFunc), "%s@yP_", data[i + 1]);
  302. //i = flen;
  303. //printf("%d %d", i, data[i]);
  304. new
  305. flen = PHP_GetNum8(data[i++]);
  306. //printf("%d", flen);
  307. //data[flen] = '\0';
  308. format(sFunc, sizeof (sFunc), "%.*s@yP_", flen, data[i]);
  309. //printf("%s", sFunc);
  310. i += flen;
  311. //printf("%d", data[i]);
  312. if (data[i] & 0x80)
  313. {
  314. flen = PHP_GetNum32(data[i]);
  315. i += 5;
  316. if (data[i] == 255)
  317. {
  318. P:5("_PHP_Result: Got number.");
  319. // Number.
  320. /*if (data[i - 1] & 0x40)
  321. {
  322. CallRemoteFunction(sFunc, "f", flen);
  323. }
  324. else
  325. {
  326. CallRemoteFunction(sFunc, "i", flen);
  327. }*/
  328. CallRemoteFunction(sFunc, "i", flen);
  329. ++i;
  330. }
  331. else
  332. {
  333. P:5("_PHP_Result: Got string.");
  334. // String.
  335. flen += i;
  336. data[flen] = '\0';
  337. CallRemoteFunction(sFunc, "s", data[i]);
  338. i = flen + 1;
  339. }
  340. }
  341. else if (data[i] & 0x40)
  342. {
  343. sFunc[flen] = '_';
  344. sFunc[flen + 3] = '@';
  345. // Function call.
  346. new
  347. params = PHP_GetNum6(data[i]),
  348. n = params * 4 + 8,
  349. heap = 0;
  350. static
  351. sFormat[64];
  352. ++i;
  353. sFormat[params] = '\0';
  354. P:5("_PHP_Result: Got function %s.", sFunc);
  355. while (params--)
  356. {
  357. if (data[i] & 0x80)
  358. {
  359. flen = PHP_GetNum32(data[i]);
  360. i += 5;
  361. if (data[i] == 255)
  362. {
  363. P:5("_PHP_Result: Got number parameter (%d).", flen);
  364. sFormat[params] = 'i';
  365. // Number.
  366. #emit LOAD.S.pri flen
  367. #emit HEAP 4
  368. #emit STOR.I
  369. #emit PUSH.alt
  370. heap += 4;
  371. ++i;
  372. }
  373. else
  374. {
  375. sFormat[params] = 's';
  376. // String
  377. flen += i;
  378. data[flen] = '\0';
  379. P:5("_PHP_Result: Got string parameter (%d: %s).", flen, data[i]);
  380. #emit LOAD.S.pri i
  381. #emit LOAD.S.alt data // Not ADDR.alt.
  382. #emit IDXADDR
  383. #emit PUSH.pri
  384. //CallRemoteFunction(sFunc, "s", data[i]);
  385. i = flen + 1;
  386. }
  387. }
  388. else if (data[i] == '1')
  389. {
  390. P:5("_PHP_Result: Got true parameter.");
  391. sFormat[params] = 'i';
  392. #emit PUSH.C sTrue
  393. ++i;
  394. }
  395. else
  396. {
  397. P:5("_PHP_Result: Got false parameter.");
  398. sFormat[params] = 'i';
  399. #emit PUSH.C sFalse
  400. ++i;
  401. }
  402. }
  403. P:5("_PHP_Result: Do function call.");
  404. // Push the static parameters and call the function.
  405. #emit PUSH.C sFormat
  406. #emit PUSH.C sFunc
  407. #emit PUSH.S n
  408. #emit SYSREQ.C CallRemoteFunction
  409. //n += 4;
  410. //#emit POP.pri
  411. // Save the return.
  412. #emit STOR.S.pri res
  413. // Clear the stack, including the return.
  414. #emit LCTRL 4
  415. #emit LOAD.S.alt n
  416. #emit ADD
  417. #emit ADD.C 4
  418. #emit SCTRL 4
  419. // Clear the heap.
  420. #emit LCTRL 2
  421. #emit LOAD.S.alt heap
  422. #emit SUB
  423. #emit SCTRL 2
  424. // Have a return.
  425. }
  426. else if (data[i] == '1')
  427. {
  428. P:5("_PHP_Result: Got true.");
  429. CallRemoteFunction(sFunc, "i", sTrue);
  430. ++i;
  431. }
  432. else
  433. {
  434. P:5("_PHP_Result: Got false.");
  435. CallRemoteFunction(sFunc, "i", sFalse);
  436. ++i;
  437. }
  438. }
  439. }
  440. case '\0':
  441. {
  442. P:E("PHP: Empty response.");
  443. }
  444. default:
  445. {
  446. // Error or unknown.
  447. switch (data[1])
  448. {
  449. case '0':
  450. {
  451. P:E("PHP: ID out of bounds.");
  452. }
  453. case '1':
  454. {
  455. P:E("PHP: Could not open shared memory.");
  456. }
  457. case '2':
  458. {
  459. //P:E("PHP: ID out of bounds.");
  460. // Not an error!
  461. }
  462. case '3':
  463. {
  464. P:F("PHP: Server does not support Shared Memory Extensions (shmop).");
  465. // Fatal error (one of only two ever)!
  466. return;
  467. }
  468. default:
  469. {
  470. P:E("PHP: Unknown error: %s.", data[1]);
  471. }
  472. }
  473. }
  474. }
  475. //new TODO;
  476. defer _PHP_FireOne(res, index);
  477. }
  478. }
  479. else
  480. {
  481. defer _PHP_FireOne[5000](0, 0);
  482. }
  483. }
  484. #define phpdata%0(%1) %0@yP_(%1);public%0@yP_(%1)
  485. #define phpfunc%0(%1) %0_yP@(%1);public%0_yP@(%1)
  486. #include "internal\y_grouprevert"