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

/usefulstuff.c

http://github.com/derickr/xdebug
C | 780 lines | 622 code | 94 blank | 64 comment | 172 complexity | 7df6d434ac635c3aafb305b15b9f9828 MD5 | raw file
Possible License(s): MPL-2.0-no-copyleft-exception
  1. /*
  2. +----------------------------------------------------------------------+
  3. | Xdebug |
  4. +----------------------------------------------------------------------+
  5. | Copyright (c) 2002-2016 Derick Rethans |
  6. +----------------------------------------------------------------------+
  7. | This source file is subject to version 1.0 of the Xdebug license, |
  8. | that is bundled with this package in the file LICENSE, and is |
  9. | available at through the world-wide-web at |
  10. | http://xdebug.derickrethans.nl/license.php |
  11. | If you did not receive a copy of the Xdebug license and are unable |
  12. | to obtain it through the world-wide-web, please send a note to |
  13. | xdebug@derickrethans.nl so we can mail you a copy immediately. |
  14. +----------------------------------------------------------------------+
  15. | Authors: Derick Rethans <derick@xdebug.org> |
  16. +----------------------------------------------------------------------+
  17. */
  18. #include <stdlib.h>
  19. #include <string.h>
  20. #ifndef WIN32
  21. #include <unistd.h>
  22. #include <sys/types.h>
  23. #include <sys/socket.h>
  24. #include <sys/time.h>
  25. #include <sys/resource.h>
  26. #include <sys/file.h>
  27. #else
  28. #define PATH_MAX MAX_PATH
  29. #include <winsock2.h>
  30. #include <io.h>
  31. #include "win32/time.h"
  32. #include <process.h>
  33. #endif
  34. #include "php_xdebug.h"
  35. #include "xdebug_mm.h"
  36. #include "xdebug_str.h"
  37. #include "usefulstuff.h"
  38. #include "ext/standard/php_lcg.h"
  39. #include "ext/standard/flock_compat.h"
  40. #include "main/php_ini.h"
  41. #ifndef NAME_MAX
  42. # ifdef _AIX
  43. # include <unistd.h>
  44. # define NAME_MAX pathconf("/dev/null",_PC_NAME_MAX)
  45. # else
  46. # define NAME_MAX (MAXNAMELEN-1)
  47. # endif
  48. #endif
  49. ZEND_EXTERN_MODULE_GLOBALS(xdebug)
  50. #define READ_BUFFER_SIZE 128
  51. char* xdebug_fd_read_line_delim(int socket, fd_buf *context, int type, unsigned char delim, int *length)
  52. {
  53. int size = 0, newl = 0, nbufsize = 0;
  54. char *tmp;
  55. char *tmp_buf = NULL;
  56. char *ptr;
  57. char buffer[READ_BUFFER_SIZE + 1];
  58. if (!context->buffer) {
  59. context->buffer = calloc(1,1);
  60. context->buffer_size = 0;
  61. }
  62. while (context->buffer_size < 1 || context->buffer[context->buffer_size - 1] != delim) {
  63. ptr = context->buffer + context->buffer_size;
  64. if (type == FD_RL_FILE) {
  65. newl = read(socket, buffer, READ_BUFFER_SIZE);
  66. } else {
  67. newl = recv(socket, buffer, READ_BUFFER_SIZE, 0);
  68. }
  69. if (newl > 0) {
  70. context->buffer = realloc(context->buffer, context->buffer_size + newl + 1);
  71. memcpy(context->buffer + context->buffer_size, buffer, newl);
  72. context->buffer_size += newl;
  73. context->buffer[context->buffer_size] = '\0';
  74. } else {
  75. return NULL;
  76. }
  77. }
  78. ptr = memchr(context->buffer, delim, context->buffer_size);
  79. size = ptr - context->buffer;
  80. /* Copy that line into tmp */
  81. tmp = malloc(size + 1);
  82. tmp[size] = '\0';
  83. memcpy(tmp, context->buffer, size);
  84. /* Rewrite existing buffer */
  85. if ((nbufsize = context->buffer_size - size - 1) > 0) {
  86. tmp_buf = malloc(nbufsize + 1);
  87. memcpy(tmp_buf, ptr + 1, nbufsize);
  88. tmp_buf[nbufsize] = 0;
  89. }
  90. free(context->buffer);
  91. context->buffer = tmp_buf;
  92. context->buffer_size = context->buffer_size - (size + 1);
  93. /* Return normal line */
  94. if (length) {
  95. *length = size;
  96. }
  97. return tmp;
  98. }
  99. char *xdebug_join(char *delim, xdebug_arg *args, int begin, int end)
  100. {
  101. int i;
  102. xdebug_str *ret;
  103. xdebug_str_ptr_init(ret);
  104. if (begin < 0) {
  105. begin = 0;
  106. }
  107. if (end > args->c - 1) {
  108. end = args->c - 1;
  109. }
  110. for (i = begin; i < end; i++) {
  111. xdebug_str_add(ret, args->args[i], 0);
  112. xdebug_str_add(ret, delim, 0);
  113. }
  114. xdebug_str_add(ret, args->args[end], 0);
  115. return ret->d;
  116. }
  117. void xdebug_explode(char *delim, char *str, xdebug_arg *args, int limit)
  118. {
  119. char *p1, *p2, *endp;
  120. endp = str + strlen(str);
  121. p1 = str;
  122. p2 = xdebug_memnstr(str, delim, strlen(delim), endp);
  123. if (p2 == NULL) {
  124. args->c++;
  125. args->args = (char**) xdrealloc(args->args, sizeof(char*) * args->c);
  126. args->args[args->c - 1] = (char*) xdmalloc(strlen(str) + 1);
  127. memcpy(args->args[args->c - 1], p1, strlen(str));
  128. args->args[args->c - 1][strlen(str)] = '\0';
  129. } else {
  130. do {
  131. args->c++;
  132. args->args = (char**) xdrealloc(args->args, sizeof(char*) * args->c);
  133. args->args[args->c - 1] = (char*) xdmalloc(p2 - p1 + 1);
  134. memcpy(args->args[args->c - 1], p1, p2 - p1);
  135. args->args[args->c - 1][p2 - p1] = '\0';
  136. p1 = p2 + strlen(delim);
  137. } while ((p2 = xdebug_memnstr(p1, delim, strlen(delim), endp)) != NULL && (limit == -1 || --limit > 1));
  138. if (p1 <= endp) {
  139. args->c++;
  140. args->args = (char**) xdrealloc(args->args, sizeof(char*) * args->c);
  141. args->args[args->c - 1] = (char*) xdmalloc(endp - p1 + 1);
  142. memcpy(args->args[args->c - 1], p1, endp - p1);
  143. args->args[args->c - 1][endp - p1] = '\0';
  144. }
  145. }
  146. }
  147. char* xdebug_memnstr(char *haystack, char *needle, int needle_len, char *end)
  148. {
  149. char *p = haystack;
  150. char first = *needle;
  151. /* let end point to the last character where needle may start */
  152. end -= needle_len;
  153. while (p <= end) {
  154. while (*p != first)
  155. if (++p > end)
  156. return NULL;
  157. if (memcmp(p, needle, needle_len) == 0)
  158. return p;
  159. p++;
  160. }
  161. return NULL;
  162. }
  163. char* xdebug_strrstr(const char* haystack, const char* needle)
  164. {
  165. char *loc = NULL;
  166. char *found = NULL;
  167. size_t pos = 0;
  168. while ((found = strstr(haystack + pos, needle)) != 0) {
  169. loc = found;
  170. pos = (found - haystack) + 1;
  171. }
  172. return loc;
  173. }
  174. double xdebug_get_utime(void)
  175. {
  176. #ifdef HAVE_GETTIMEOFDAY
  177. struct timeval tp;
  178. long sec = 0L;
  179. double msec = 0.0;
  180. if (gettimeofday((struct timeval *) &tp, NULL) == 0) {
  181. sec = tp.tv_sec;
  182. msec = (double) (tp.tv_usec / MICRO_IN_SEC);
  183. if (msec >= 1.0) {
  184. msec -= (long) msec;
  185. }
  186. return msec + sec;
  187. }
  188. #endif
  189. return 0;
  190. }
  191. char* xdebug_get_time(void)
  192. {
  193. time_t cur_time;
  194. char *str_time;
  195. str_time = xdmalloc(24);
  196. cur_time = time(NULL);
  197. strftime(str_time, 24, "%Y-%m-%d %H:%M:%S", gmtime (&cur_time));
  198. return str_time;
  199. }
  200. /* not all versions of php export this */
  201. static int xdebug_htoi(char *s)
  202. {
  203. int value;
  204. int c;
  205. c = s[0];
  206. if (isupper(c)) {
  207. c = tolower(c);
  208. }
  209. value = (c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10) * 16;
  210. c = s[1];
  211. if (isupper(c)) {
  212. c = tolower(c);
  213. }
  214. value += c >= '0' && c <= '9' ? c - '0' : c - 'a' + 10;
  215. return value;
  216. }
  217. /* not all versions of php export this */
  218. int xdebug_raw_url_decode(char *str, int len)
  219. {
  220. char *dest = str;
  221. char *data = str;
  222. while (len--) {
  223. if (*data == '%' && len >= 2 && isxdigit((int) *(data + 1)) && isxdigit((int) *(data + 2))) {
  224. *dest = (char) xdebug_htoi(data + 1);
  225. data += 2;
  226. len -= 2;
  227. } else {
  228. *dest = *data;
  229. }
  230. data++;
  231. dest++;
  232. }
  233. *dest = '\0';
  234. return dest - str;
  235. }
  236. static unsigned char hexchars[] = "0123456789ABCDEF";
  237. char *xdebug_raw_url_encode(char const *s, int len, int *new_length, int skip_slash)
  238. {
  239. register int x, y;
  240. unsigned char *str;
  241. str = (unsigned char *) xdmalloc(3 * len + 1);
  242. for (x = 0, y = 0; len--; x++, y++) {
  243. str[y] = (unsigned char) s[x];
  244. if ((str[y] < '0' && str[y] != '-' && str[y] != '.' && (str[y] != '/' || !skip_slash)) ||
  245. (str[y] < 'A' && str[y] > '9' && str[y] != ':') ||
  246. (str[y] > 'Z' && str[y] < 'a' && str[y] != '_' && (str[y] != '\\' || !skip_slash)) ||
  247. (str[y] > 'z'))
  248. {
  249. str[y++] = '%';
  250. str[y++] = hexchars[(unsigned char) s[x] >> 4];
  251. str[y] = hexchars[(unsigned char) s[x] & 15];
  252. }
  253. }
  254. str[y] = '\0';
  255. if (new_length) {
  256. *new_length = y;
  257. }
  258. return ((char *) str);
  259. }
  260. /* fake URI's per IETF RFC 1738 and 2396 format */
  261. char *xdebug_path_from_url(const char *fileurl TSRMLS_DC)
  262. {
  263. /* deal with file: url's */
  264. char *dfp = NULL;
  265. const char *fp = NULL, *efp = fileurl;
  266. #ifdef PHP_WIN32
  267. int l = 0;
  268. int i;
  269. #endif
  270. char *tmp = NULL, *ret = NULL;
  271. dfp = xdstrdup(efp);
  272. fp = dfp;
  273. xdebug_raw_url_decode(dfp, strlen(dfp));
  274. tmp = strstr(fp, "file://");
  275. if (tmp) {
  276. fp = tmp + 7;
  277. if (fp[0] == '/' && fp[2] == ':') {
  278. fp++;
  279. }
  280. ret = xdstrdup(fp);
  281. #ifdef PHP_WIN32
  282. l = strlen(ret);
  283. /* convert '/' to '\' */
  284. for (i = 0; i < l; i++) {
  285. if (ret[i] == '/') {
  286. ret[i] = '\\';
  287. }
  288. }
  289. #endif
  290. } else {
  291. ret = xdstrdup(fileurl);
  292. }
  293. free(dfp);
  294. return ret;
  295. }
  296. /* fake URI's per IETF RFC 1738 and 2396 format */
  297. char *xdebug_path_to_url(const char *fileurl TSRMLS_DC)
  298. {
  299. int l, i, new_len;
  300. char *tmp = NULL;
  301. char *encoded_fileurl;
  302. /* encode the url */
  303. encoded_fileurl = xdebug_raw_url_encode(fileurl, strlen(fileurl), &new_len, 1);
  304. if (strncmp(fileurl, "phar://", 7) == 0) {
  305. /* ignore, phar is cool */
  306. tmp = xdstrdup(fileurl);
  307. } else if (fileurl[0] != '/' && fileurl[0] != '\\' && fileurl[1] != ':') {
  308. /* convert relative paths */
  309. cwd_state new_state;
  310. char cwd[MAXPATHLEN];
  311. char *result;
  312. result = VCWD_GETCWD(cwd, MAXPATHLEN);
  313. if (!result) {
  314. cwd[0] = '\0';
  315. }
  316. #if PHP_VERSION_ID >= 50600
  317. new_state.cwd = estrdup(cwd);
  318. #else
  319. new_state.cwd = strdup(cwd);
  320. #endif
  321. new_state.cwd_length = strlen(cwd);
  322. if (!virtual_file_ex(&new_state, fileurl, NULL, 1 TSRMLS_CC)) {
  323. char *s = estrndup(new_state.cwd, new_state.cwd_length);
  324. tmp = xdebug_sprintf("file://%s",s);
  325. efree(s);
  326. }
  327. #if PHP_VERSION_ID >= 50600
  328. efree(new_state.cwd);
  329. #else
  330. free(new_state.cwd);
  331. #endif
  332. } else if (fileurl[1] == '/' || fileurl[1] == '\\') {
  333. /* convert UNC paths (eg. \\server\sharepath) */
  334. /* See http://blogs.msdn.com/ie/archive/2006/12/06/file-uris-in-windows.aspx */
  335. tmp = xdebug_sprintf("file:%s", encoded_fileurl);
  336. } else if (fileurl[0] == '/' || fileurl[0] == '\\') {
  337. /* convert *nix paths (eg. /path) */
  338. tmp = xdebug_sprintf("file://%s", encoded_fileurl);
  339. } else if (fileurl[1] == ':') {
  340. /* convert windows drive paths (eg. c:\path) */
  341. tmp = xdebug_sprintf("file:///%s", encoded_fileurl);
  342. } else {
  343. /* no clue about it, use it raw */
  344. tmp = xdstrdup(encoded_fileurl);
  345. }
  346. l = strlen(tmp);
  347. /* convert '\' to '/' */
  348. for (i = 0; i < l; i++) {
  349. if (tmp[i] == '\\') {
  350. tmp[i]='/';
  351. }
  352. }
  353. xdfree(encoded_fileurl);
  354. return tmp;
  355. }
  356. long xdebug_crc32(const char *string, int str_len)
  357. {
  358. unsigned int crc = ~0;
  359. int len;
  360. len = 0 ;
  361. for (len += str_len; str_len--; ++string) {
  362. XDEBUG_CRC32(crc, *string);
  363. }
  364. return ~crc;
  365. }
  366. #ifndef PHP_WIN32
  367. static FILE *xdebug_open_file(char *fname, char *mode, char *extension, char **new_fname)
  368. {
  369. FILE *fh;
  370. char *tmp_fname;
  371. if (extension) {
  372. tmp_fname = xdebug_sprintf("%s.%s", fname, extension);
  373. } else {
  374. tmp_fname = xdstrdup(fname);
  375. }
  376. fh = fopen(tmp_fname, mode);
  377. if (fh && new_fname) {
  378. *new_fname = tmp_fname;
  379. } else {
  380. xdfree(tmp_fname);
  381. }
  382. return fh;
  383. }
  384. static FILE *xdebug_open_file_with_random_ext(char *fname, char *mode, char *extension, char **new_fname)
  385. {
  386. FILE *fh;
  387. char *tmp_fname;
  388. TSRMLS_FETCH();
  389. if (extension) {
  390. tmp_fname = xdebug_sprintf("%s.%06x.%s", fname, (long) (1000000 * php_combined_lcg(TSRMLS_C)), extension);
  391. } else {
  392. tmp_fname = xdebug_sprintf("%s.%06x", fname, (long) (1000000 * php_combined_lcg(TSRMLS_C)), extension);
  393. }
  394. fh = fopen(tmp_fname, mode);
  395. if (fh && new_fname) {
  396. *new_fname = tmp_fname;
  397. } else {
  398. xdfree(tmp_fname);
  399. }
  400. return fh;
  401. }
  402. FILE *xdebug_fopen(char *fname, char *mode, char *extension, char **new_fname)
  403. {
  404. int r;
  405. FILE *fh;
  406. struct stat buf;
  407. char *tmp_fname = NULL;
  408. int filename_len = 0;
  409. /* We're not doing any tricks for append mode... as that has atomic writes
  410. * anyway. And we ignore read mode as well. */
  411. if (mode[0] == 'a' || mode[0] == 'r') {
  412. return xdebug_open_file(fname, mode, extension, new_fname);
  413. }
  414. /* Make sure we don't open a file with a path that's too long */
  415. filename_len += (fname ? strlen(fname) : 0); /* filename */
  416. filename_len += (extension ? strlen(extension) : 0) + 1; /* extension (+ ".") */
  417. filename_len += 8; /* possible random extension (+ ".") */
  418. if (filename_len > NAME_MAX) {
  419. fname[NAME_MAX - (extension ? strlen(extension) : 0 )] = '\0';
  420. }
  421. /* In write mode however we do have to do some stuff. */
  422. /* 1. Check if the file exists */
  423. if (extension) {
  424. tmp_fname = xdebug_sprintf("%s.%s", fname, extension);
  425. } else {
  426. tmp_fname = xdstrdup(fname);
  427. }
  428. r = stat(tmp_fname, &buf);
  429. /* We're not freeing "tmp_fname" as that is used in the freopen as well. */
  430. if (r == -1) {
  431. /* 2. Cool, the file doesn't exist so we can open it without probs now. */
  432. fh = xdebug_open_file(fname, "w", extension, new_fname);
  433. goto lock;
  434. }
  435. /* 3. It exists, check if we can open it. */
  436. fh = xdebug_open_file(fname, "r+", extension, new_fname);
  437. if (!fh) {
  438. /* 4. If fh == null we couldn't even open the file, so open a new one with a new name */
  439. fh = xdebug_open_file_with_random_ext(fname, "w", extension, new_fname);
  440. goto lock;
  441. }
  442. /* 5. It exists and we can open it, check if we can exclusively lock it. */
  443. r = flock(fileno(fh), LOCK_EX | LOCK_NB);
  444. if (r == -1) {
  445. if (errno == EWOULDBLOCK) {
  446. fclose(fh);
  447. /* 6. The file is in use, so we open one with a new name. */
  448. fh = xdebug_open_file_with_random_ext(fname, "w", extension, new_fname);
  449. goto lock;
  450. }
  451. }
  452. /* 7. We established a lock, now we truncate and return the handle */
  453. fh = freopen(tmp_fname, "w", fh);
  454. lock: /* Yes yes, an evil goto label here!!! */
  455. if (fh) {
  456. /* 8. We have to lock again after the reopen as that basically closes
  457. * the file and opens it again. There is a small race condition here...
  458. */
  459. flock(fileno(fh), LOCK_EX | LOCK_NB);
  460. }
  461. xdfree(tmp_fname);
  462. return fh;
  463. }
  464. #else
  465. FILE *xdebug_fopen(char *fname, char *mode, char *extension, char **new_fname)
  466. {
  467. char *tmp_fname;
  468. FILE *ret;
  469. if (extension) {
  470. tmp_fname = xdebug_sprintf("%s.%s", fname, extension);
  471. } else {
  472. tmp_fname = xdstrdup(fname);
  473. }
  474. ret = fopen(tmp_fname, mode);
  475. if (new_fname) {
  476. *new_fname = tmp_fname;
  477. } else {
  478. xdfree(tmp_fname);
  479. }
  480. return ret;
  481. }
  482. #endif
  483. int xdebug_format_output_filename(char **filename, char *format, char *script_name)
  484. {
  485. xdebug_str fname = XDEBUG_STR_INITIALIZER;
  486. char cwd[128];
  487. TSRMLS_FETCH();
  488. while (*format)
  489. {
  490. if (*format != '%') {
  491. xdebug_str_addl(&fname, (char *) format, 1, 0);
  492. } else {
  493. format++;
  494. switch (*format)
  495. {
  496. case 'c': /* crc32 of the current working directory */
  497. if (VCWD_GETCWD(cwd, 127)) {
  498. xdebug_str_add(&fname, xdebug_sprintf("%lu", xdebug_crc32(cwd, strlen(cwd))), 1);
  499. }
  500. break;
  501. case 'p': /* pid */
  502. xdebug_str_add(&fname, xdebug_sprintf("%ld", getpid()), 1);
  503. break;
  504. case 'r': /* random number */
  505. xdebug_str_add(&fname, xdebug_sprintf("%06x", (long) (1000000 * php_combined_lcg(TSRMLS_C))), 1);
  506. break;
  507. case 's': { /* script fname */
  508. char *char_ptr, *script_name_tmp;
  509. /* we do not always have script_name available, so if we
  510. * don't have it and this format specifier is used then we
  511. * simple do nothing for this specifier */
  512. if (!script_name) {
  513. break;
  514. }
  515. /* create a copy to work on */
  516. script_name_tmp = xdstrdup(script_name);
  517. /* replace slashes, whitespace and colons with underscores */
  518. while ((char_ptr = strpbrk(script_name_tmp, "/\\: ")) != NULL) {
  519. char_ptr[0] = '_';
  520. }
  521. /* replace .php with _php */
  522. char_ptr = strrchr(script_name_tmp, '.');
  523. if (char_ptr) {
  524. char_ptr[0] = '_';
  525. }
  526. xdebug_str_add(&fname, script_name_tmp, 0);
  527. xdfree(script_name_tmp);
  528. } break;
  529. case 't': { /* timestamp (in seconds) */
  530. time_t the_time = time(NULL);
  531. xdebug_str_add(&fname, xdebug_sprintf("%ld", the_time), 1);
  532. } break;
  533. case 'u': { /* timestamp (in microseconds) */
  534. char *char_ptr, *utime = xdebug_sprintf("%F", xdebug_get_utime());
  535. /* Replace . with _ (or should it be nuked?) */
  536. char_ptr = strrchr(utime, '.');
  537. if (char_ptr) {
  538. char_ptr[0] = '_';
  539. }
  540. xdebug_str_add(&fname, utime, 1);
  541. } break;
  542. case 'H': /* $_SERVER['HTTP_HOST'] */
  543. case 'U': /* $_SERVER['UNIQUE_ID'] */
  544. case 'R': { /* $_SERVER['REQUEST_URI'] */
  545. char *char_ptr, *strval;
  546. #if PHP_VERSION_ID >= 70000
  547. zval *data = NULL;
  548. if (Z_TYPE(PG(http_globals)[TRACK_VARS_SERVER]) == IS_ARRAY) {
  549. switch (*format) {
  550. case 'H':
  551. data = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_HOST", sizeof("HTTP_HOST") - 1);
  552. break;
  553. case 'R':
  554. data = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "REQUEST_URI", sizeof("REQUEST_URI") - 1);
  555. break;
  556. case 'U':
  557. data = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "UNIQUE_ID", sizeof("UNIQUE_ID") - 1);
  558. break;
  559. }
  560. if (data) {
  561. strval = estrdup(Z_STRVAL_P(data));
  562. #else
  563. int retval = FAILURE;
  564. zval **data;
  565. if (PG(http_globals)[TRACK_VARS_SERVER]) {
  566. switch (*format) {
  567. case 'H':
  568. retval = zend_hash_find(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_HOST", sizeof("HTTP_HOST"), (void **) &data);
  569. break;
  570. case 'R':
  571. retval = zend_hash_find(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]), "REQUEST_URI", sizeof("REQUEST_URI"), (void **) &data);
  572. break;
  573. case 'U':
  574. retval = zend_hash_find(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_SERVER]), "UNIQUE_ID", sizeof("UNIQUE_ID"), (void **) &data);
  575. break;
  576. }
  577. if (retval == SUCCESS) {
  578. strval = estrdup(Z_STRVAL_PP(data));
  579. #endif
  580. /* replace slashes, dots, question marks, plus
  581. * signs, ampersands, spaces and other evil chars
  582. * with underscores */
  583. while ((char_ptr = strpbrk(strval, "/\\.?&+:*\"<>| ")) != NULL) {
  584. char_ptr[0] = '_';
  585. }
  586. xdebug_str_add(&fname, strval, 0);
  587. efree(strval);
  588. }
  589. }
  590. } break;
  591. case 'S': { /* session id */
  592. #if PHP_VERSION_ID >= 70000
  593. zval *data;
  594. #else
  595. zval **data;
  596. #endif
  597. char *char_ptr, *strval;
  598. char *sess_name;
  599. sess_name = zend_ini_string("session.name", sizeof("session.name"), 0);
  600. #if PHP_VERSION_ID >= 70000
  601. if (sess_name && Z_TYPE(PG(http_globals)[TRACK_VARS_COOKIE]) == IS_ARRAY &&
  602. ((data = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_COOKIE]), sess_name, strlen(sess_name))) != NULL) &&
  603. Z_STRLEN_P(data) < 100 /* Prevent any unrealistically long data being set as filename */
  604. ) {
  605. strval = estrdup(Z_STRVAL_P(data));
  606. #else
  607. if (sess_name && PG(http_globals)[TRACK_VARS_COOKIE] &&
  608. zend_hash_find(Z_ARRVAL_P(PG(http_globals)[TRACK_VARS_COOKIE]), sess_name, strlen(sess_name) + 1, (void **) &data) == SUCCESS &&
  609. Z_STRLEN_PP(data) < 100 /* Prevent any unrealistically long data being set as filename */
  610. ) {
  611. strval = estrdup(Z_STRVAL_PP(data));
  612. #endif
  613. /* replace slashes, dots, question marks, plus signs,
  614. * ampersands and spaces with underscores */
  615. while ((char_ptr = strpbrk(strval, "/\\.?&+ ")) != NULL) {
  616. char_ptr[0] = '_';
  617. }
  618. xdebug_str_add(&fname, strval, 0);
  619. efree(strval);
  620. }
  621. } break;
  622. case '%': /* literal % */
  623. xdebug_str_addl(&fname, "%", 1, 0);
  624. break;
  625. }
  626. }
  627. format++;
  628. }
  629. *filename = fname.d;
  630. return fname.l;
  631. }
  632. int xdebug_format_file_link(char **filename, const char *error_filename, int error_lineno TSRMLS_DC)
  633. {
  634. xdebug_str fname = XDEBUG_STR_INITIALIZER;
  635. char *format = XG(file_link_format);
  636. while (*format)
  637. {
  638. if (*format != '%') {
  639. xdebug_str_addl(&fname, (char *) format, 1, 0);
  640. } else {
  641. format++;
  642. switch (*format)
  643. {
  644. case 'f': /* filename */
  645. xdebug_str_add(&fname, xdebug_sprintf("%s", error_filename), 1);
  646. break;
  647. case 'l': /* line number */
  648. xdebug_str_add(&fname, xdebug_sprintf("%d", error_lineno), 1);
  649. break;
  650. case '%': /* literal % */
  651. xdebug_str_addl(&fname, "%", 1, 0);
  652. break;
  653. }
  654. }
  655. format++;
  656. }
  657. *filename = fname.d;
  658. return fname.l;
  659. }
  660. void xdebug_open_log(TSRMLS_D)
  661. {
  662. /* initialize remote log file */
  663. XG(remote_log_file) = NULL;
  664. if (XG(remote_log) && strlen(XG(remote_log))) {
  665. XG(remote_log_file) = xdebug_fopen(XG(remote_log), "a", NULL, NULL);
  666. }
  667. if (XG(remote_log_file)) {
  668. char *timestr = xdebug_get_time();
  669. fprintf(XG(remote_log_file), "Log opened at %s\n", timestr);
  670. fflush(XG(remote_log_file));
  671. xdfree(timestr);
  672. } else if (strlen(XG(remote_log))) {
  673. php_log_err(xdebug_sprintf("XDebug could not open the remote debug file '%s'.", XG(remote_log)) TSRMLS_CC);
  674. }
  675. }
  676. void xdebug_close_log(TSRMLS_D)
  677. {
  678. if (XG(remote_log_file)) {
  679. char *timestr = xdebug_get_time();
  680. fprintf(XG(remote_log_file), "Log closed at %s\n\n", timestr);
  681. fflush(XG(remote_log_file));
  682. xdfree(timestr);
  683. fclose(XG(remote_log_file));
  684. XG(remote_log_file) = NULL;
  685. }
  686. }