y_php.inc 13 KB

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