1 Star 0 Fork 0

yanghuangsheng / sdebug

加入 Gitee
与超过 1200万 开发者一起发现、参与优秀开源项目,私有仓库也完全免费 :)
免费加入
克隆/下载
xdebug_com.c 19.93 KB
一键复制 编辑 原始数据 按行查看 历史
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607
/*
+----------------------------------------------------------------------+
| Xdebug |
+----------------------------------------------------------------------+
| Copyright (c) 2002-2018 Derick Rethans |
+----------------------------------------------------------------------+
| This source file is subject to version 1.01 of the Xdebug license, |
| that is bundled with this package in the file LICENSE, and is |
| available at through the world-wide-web at |
| https://xdebug.org/license.php |
| If you did not receive a copy of the Xdebug license and are unable |
| to obtain it through the world-wide-web, please send a note to |
| derick@xdebug.org so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Derick Rethans <derick@xdebug.org> |
| Thomas Vanhaniemi <thomas.vanhaniemi@arcada.fi> |
+----------------------------------------------------------------------+
*/
#include "php_xdebug.h"
#include <string.h>
#include <sys/types.h>
#include <errno.h>
#include <stdio.h>
#include <fcntl.h>
#ifndef PHP_WIN32
# if HAVE_POLL_H
# include <poll.h>
# elif HAVE_SYS_POLL_H
# include <sys/poll.h>
# endif
# include <unistd.h>
# include <sys/socket.h>
# include <sys/un.h>
# include <netinet/tcp.h>
# if HAVE_NETINET_IN_H
# include <netinet/in.h>
# endif
# include <netdb.h>
#else
# include <process.h>
# include <direct.h>
# include "win32/time.h"
# undef UNICODE
# include <winsock2.h>
# include <ws2tcpip.h>
# include <mstcpip.h>
# pragma comment (lib, "Ws2_32.lib")
# define PATH_MAX MAX_PATH
# define poll WSAPoll
#endif
#include "xdebug_private.h"
#include "xdebug_com.h"
ZEND_EXTERN_MODULE_GLOBALS(xdebug)
#if !WIN32 && !WINNT
static int xdebug_create_socket_unix(const char *path TSRMLS_DC)
{
struct sockaddr_un sa;
int sockfd;
long pid = getpid();
if ((sockfd = socket(AF_UNIX, SOCK_STREAM, 0)) == SOCK_ERR) {
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for 'unix://%s', socket: %s.\n", pid, path, strerror(errno));
return SOCK_ERR;
}
sa.sun_family = AF_UNIX;
strncpy(sa.sun_path, path, sizeof(sa.sun_path) - 1);
if (connect(sockfd, (struct sockaddr*)&sa, sizeof(sa)) < 0) {
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for 'unix://%s', connect: %s.\n", pid, path, strerror(errno));
SCLOSE(sockfd);
return (errno == EACCES) ? SOCK_ACCESS_ERR : SOCK_ERR;
}
/* Prevent the socket from being inherited by exec'd children */
if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) < 0) {
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for 'unix://%s', fcntl(FD_CLOEXEC): %s.\n", pid, path, strerror(errno));
}
return sockfd;
}
#endif
int xdebug_create_socket(const char *hostname, int dport, int timeout TSRMLS_DC)
{
struct addrinfo hints;
struct addrinfo *remote;
struct addrinfo *ptr;
int status;
int sockfd = 0;
int sockerror;
char sport[10];
int actually_connected;
struct sockaddr_in6 sa;
socklen_t size = sizeof(sa);
long pid = getpid();
#if WIN32|WINNT
WSAPOLLFD ufds[1] = {0};
WORD wVersionRequested;
WSADATA wsaData;
char optval = 1;
u_long yes = 1;
u_long no = 0;
wVersionRequested = MAKEWORD(2, 2);
WSAStartup(wVersionRequested, &wsaData);
#else
struct pollfd ufds[1];
long optval = 1;
#endif
if (!strncmp(hostname, "unix://", strlen("unix://"))) {
#if WIN32|WINNT
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for '%s', Unix domain socket not supported.\n", pid, hostname);
return SOCK_ERR;
#else
return xdebug_create_socket_unix(hostname + strlen("unix://") TSRMLS_CC);
#endif
}
/* Make a string of the port number that can be used with getaddrinfo */
sprintf(sport, "%d", dport);
/* Create hints for getaddrinfo saying that we want IPv4 and IPv6 TCP stream sockets */
memset(&hints, 0, sizeof(hints));
hints.ai_family = AF_UNSPEC;
hints.ai_socktype = SOCK_STREAM;
hints.ai_protocol = IPPROTO_TCP;
hints.ai_flags = AI_PASSIVE;
/* Call getaddrinfo and return SOCK_ERR if the call fails for some reason */
if ((status = getaddrinfo(hostname, sport, &hints, &remote)) != 0) {
#if WIN32|WINNT
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for '%s:%d', getaddrinfo: %d.\n", pid, hostname, dport, WSAGetLastError());
#else
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for '%s:%d', getaddrinfo: %s.\n", pid, hostname, dport, strerror(errno));
#endif
return SOCK_ERR;
}
/* Go through every returned IP address */
for (ptr = remote; ptr != NULL; ptr = ptr->ai_next) {
/* Try to create the socket. If the creation fails continue on with the
* next IP address in the list */
if ((sockfd = socket(ptr->ai_family, ptr->ai_socktype, ptr->ai_protocol)) == SOCK_ERR) {
#if WIN32|WINNT
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for '%s:%d', socket: %d.\n", pid, hostname, dport, WSAGetLastError());
#else
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for '%s:%d', socket: %s.\n", pid, hostname, dport, strerror(errno));
#endif
continue;
}
/* Put socket in non-blocking mode so we can use poll for timeouts */
#ifdef WIN32
status = ioctlsocket(sockfd, FIONBIO, &yes);
if (SOCKET_ERROR == status) {
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for '%s:%d', FIONBIO: %d.\n", pid, hostname, dport, WSAGetLastError());
}
#else
fcntl(sockfd, F_SETFL, O_NONBLOCK);
#endif
#if !WIN32 && !WINNT
/* Prevent the socket from being inherited by exec'd children on *nix (not necessary on Win) */
if (fcntl(sockfd, F_SETFD, FD_CLOEXEC) < 0) {
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for '%s:%d', fcntl(FD_CLOEXEC): %s.\n", pid, hostname, dport, strerror(errno));
}
#endif
/* Try to connect to the newly created socket */
/* Worth noting is that the port is set in the getaddrinfo call before */
status = connect(sockfd, ptr->ai_addr, ptr->ai_addrlen);
/* Determine if we got a connection. If no connection could be made
* we close the socket and continue with the next IP address in the list */
if (status < 0) {
#ifdef WIN32
errno = WSAGetLastError();
if (errno != WSAEINPROGRESS && errno != WSAEWOULDBLOCK) {
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for '%s:%d', connect: %d.\n", pid, hostname, dport, errno);
#else
if (errno == EACCES) {
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for '%s:%d', connect: %s.\n", pid, hostname, dport, strerror(errno));
SCLOSE(sockfd);
sockfd = SOCK_ACCESS_ERR;
continue;
}
if (errno != EINPROGRESS) {
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for '%s:%d', connect: %s.\n", pid, hostname, dport, strerror(errno));
#endif
SCLOSE(sockfd);
sockfd = SOCK_ERR;
continue;
}
ufds[0].fd = sockfd;
#if WIN32|WINNT
ufds[0].events = POLLIN | POLLOUT;
#else
ufds[0].events = POLLIN | POLLOUT | POLLPRI;
#endif
while (1) {
sockerror = poll(ufds, 1, timeout);
#if WIN32|WINNT
errno = WSAGetLastError();
if (errno == WSAEINPROGRESS || errno == WSAEWOULDBLOCK) {
/* XXX introduce retry count? */
continue;
}
#endif
/* If an error occured when doing the poll */
if (sockerror == SOCK_ERR) {
#if WIN32|WINNT
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for '%s:%d', WSAPoll error: %d (%d, %d).\n", pid, hostname, dport, WSAGetLastError(), sockerror, errno);
#else
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for '%s:%d', poll error: %s (%d).\n", pid, hostname, dport, strerror(errno), sockerror);
#endif
sockerror = SOCK_ERR;
break;
}
/* A timeout occured when polling the socket */
if (sockerror == 0) {
sockerror = SOCK_TIMEOUT_ERR;
break;
}
/* If the poll was successful but an error occured */
if (ufds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
#if WIN32|WINNT
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for '%s:%d', WSAPoll success, but error: %d (%d).\n", pid, hostname, dport, WSAGetLastError(), ufds[0].revents);
#else
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for '%s:%d', poll success, but error: %s (%d).\n", pid, hostname, dport, strerror(errno), ufds[0].revents);
#endif
sockerror = SOCK_ERR;
break;
}
/* If the poll was successful break out */
if (ufds[0].revents & (POLLIN | POLLOUT)) {
sockerror = sockfd;
break;
} else {
/* We should never get here, but added as a failsafe to break out from any loops */
#if WIN32|WINNT
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for '%s:%d', WSAPoll: %d.\n", pid, hostname, dport, WSAGetLastError());
#else
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for '%s:%d', poll: %s.\n", pid, hostname, dport, strerror(errno));
#endif
sockerror = SOCK_ERR;
break;
}
}
if (sockerror > 0) {
actually_connected = getpeername(sockfd, (struct sockaddr *)&sa, &size);
if (actually_connected == -1) {
#if WIN32|WINNT
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for '%s:%d', getpeername: %d.\n", pid, hostname, dport, WSAGetLastError());
#else
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for '%s:%d', getpeername: %s.\n", pid, hostname, dport, strerror(errno));
#endif
sockerror = SOCK_ERR;
}
}
/* If there where some errors close the socket and continue with the next IP address */
if (sockerror < 0) {
SCLOSE(sockfd);
sockfd = sockerror;
continue;
}
}
break;
}
/* Free the result returned by getaddrinfo */
freeaddrinfo(remote);
/* If we got a socket, set the option "No delay" to true (1) */
if (sockfd > 0) {
#ifdef WIN32
status = ioctlsocket(sockfd, FIONBIO, &no);
if (SOCKET_ERROR == status) {
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Creating socket for '%s:%d', FIONBIO: %d.\n", pid, hostname, dport, WSAGetLastError());
}
#else
fcntl(sockfd, F_SETFL, 0);
#endif
setsockopt(sockfd, IPPROTO_TCP, TCP_NODELAY, &optval, sizeof(optval));
}
return sockfd;
}
void xdebug_close_socket(int socketfd)
{
SCLOSE(socketfd);
}
/* Remote debugger helper functions */
int xdebug_handle_hit_value(xdebug_brk_info *brk_info)
{
/* If this is a temporary breakpoint, disable the breakpoint */
if (brk_info->temporary) {
brk_info->disabled = 1;
}
/* Increase hit counter */
brk_info->hit_count++;
/* If the hit_value is 0, the condition check is disabled */
if (!brk_info->hit_value) {
return 1;
}
switch (brk_info->hit_condition) {
case XDEBUG_HIT_GREATER_EQUAL:
if (brk_info->hit_count >= brk_info->hit_value) {
return 1;
}
break;
case XDEBUG_HIT_EQUAL:
if (brk_info->hit_count == brk_info->hit_value) {
return 1;
}
break;
case XDEBUG_HIT_MOD:
if (brk_info->hit_count % brk_info->hit_value == 0) {
return 1;
}
break;
case XDEBUG_HIT_DISABLED:
return 1;
break;
}
return 0;
}
/* Log related functions */
static void xdebug_open_log(void)
{
long pid = getpid();
/* initialize remote log file */
XG(remote_log_file) = NULL;
if (XG(remote_log) && strlen(XG(remote_log))) {
XG(remote_log_file) = xdebug_fopen(XG(remote_log), "a", NULL, NULL);
}
if (XG(remote_log_file)) {
char *timestr = xdebug_get_time();
fprintf(XG(remote_log_file), "[%ld] Log opened at %s\n", pid, timestr);
fflush(XG(remote_log_file));
xdfree(timestr);
} else if (strlen(XG(remote_log))) {
php_log_err(xdebug_sprintf("Xdebug could not open the remote debug file '%s'.", XG(remote_log)));
}
}
static void xdebug_close_log()
{
if (XG(remote_log_file)) {
long pid = getpid();
char *timestr = xdebug_get_time();
fprintf(XG(remote_log_file), "[%ld] Log closed at %s\n[%ld]\n", pid, timestr, pid);
fflush(XG(remote_log_file));
xdfree(timestr);
fclose(XG(remote_log_file));
XG(remote_log_file) = NULL;
}
}
/* Starting the debugger */
static void xdebug_init_debugger()
{
long pid = getpid();
xdebug_open_log();
if (XG(remote_connect_back)) {
zval *remote_addr = NULL;
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] I: Checking remote connect back address.\n", pid);
if (XG(remote_addr_header) && XG(remote_addr_header)[0]) {
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] I: Checking user configured header '%s'.\n", pid, XG(remote_addr_header));
remote_addr = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), XG(remote_addr_header), HASH_KEY_STRLEN(XG(remote_addr_header)));
}
if (!remote_addr) {
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] I: Checking header 'HTTP_X_FORWARDED_FOR'.\n", pid);
remote_addr = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "HTTP_X_FORWARDED_FOR", HASH_KEY_SIZEOF("HTTP_X_FORWARDED_FOR"));
}
if (!remote_addr) {
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] I: Checking header 'REMOTE_ADDR'.\n", pid);
remote_addr = zend_hash_str_find(Z_ARRVAL(PG(http_globals)[TRACK_VARS_SERVER]), "REMOTE_ADDR", HASH_KEY_SIZEOF("REMOTE_ADDR"));
}
if (remote_addr && strstr(Z_STRVAL_P(remote_addr), "://")) {
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Invalid remote address provided containing URI spec '%s'.\n", pid, Z_STRVAL_P(remote_addr));
remote_addr = NULL;
}
if (remote_addr) {
/* Use first IP according to RFC 7239 */
char *cp = strchr(Z_STRVAL_P(remote_addr), ',');
if (cp) {
*cp = '\0';
}
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] I: Remote address found, connecting to %s:%ld.\n", pid, Z_STRVAL_P(remote_addr), (long int) XG(remote_port));
XG(context).socket = xdebug_create_socket(Z_STRVAL_P(remote_addr), XG(remote_port), XG(remote_connect_timeout));
} else {
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] W: Remote address not found, connecting to configured address/port: %s:%ld. :-|\n", pid, XG(remote_host), (long int) XG(remote_port));
XG(context).socket = xdebug_create_socket(XG(remote_host), XG(remote_port), XG(remote_connect_timeout));
}
} else {
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] I: Connecting to configured address/port: %s:%ld.\n", pid, XG(remote_host), (long int) XG(remote_port));
XG(context).socket = xdebug_create_socket(XG(remote_host), XG(remote_port), XG(remote_connect_timeout));
}
if (XG(context).socket >= 0) {
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] I: Connected to client. :-)\n", pid);
xdebug_mark_debug_connection_pending();
/* Get handler from mode */
XG(context).handler = xdebug_handler_get(XG(remote_handler));
if (!XG(context).handler) {
zend_error(E_WARNING, "The remote debug handler '%s' is not supported.", XG(remote_handler));
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] E: The remote debug handler '%s' is not supported. :-(\n", pid, XG(remote_handler));
} else if (!XG(context).handler->remote_init(&(XG(context)), XDEBUG_REQ)) {
/* The request could not be started, ignore it then */
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] E: The debug session could not be started. :-(\n", pid);
} else {
/* All is well, turn off script time outs */
zend_string *ini_name = zend_string_init("max_execution_time", sizeof("max_execution_time") - 1, 0);
zend_string *ini_val = zend_string_init("0", sizeof("0") - 1, 0);
zend_alter_ini_entry(ini_name, ini_val, PHP_INI_SYSTEM, PHP_INI_STAGE_ACTIVATE);
zend_string_release(ini_val);
zend_string_release(ini_name);
xdebug_mark_debug_connection_active();
}
} else if (XG(context).socket == -1) {
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] E: Could not connect to client. :-(\n", pid);
} else if (XG(context).socket == -2) {
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] E: Time-out connecting to client (Waited: " ZEND_LONG_FMT " ms). :-(\n", pid, XG(remote_connect_timeout));
} else if (XG(context).socket == -3) {
XDEBUG_LOG_PRINT(XG(remote_log_file), "[%ld] E: No permission connecting to client. This could be SELinux related. :-(\n", pid);
}
if (!XG(remote_connection_enabled)) {
xdebug_close_log();
}
}
void xdebug_abort_debugger()
{
if (XG(remote_connection_enabled)) {
xdebug_mark_debug_connection_not_active();
}
}
void xdebug_restart_debugger()
{
xdebug_abort_debugger();
xdebug_init_debugger();
}
/* Remote connection activation and house keeping */
int xdebug_is_debug_connection_active()
{
return (
XG(remote_connection_enabled)
);
}
int xdebug_is_debug_connection_active_for_current_pid()
{
/* Start debugger if previously a connection was established and this
* process no longer has the same PID */
if ((xdebug_is_debug_connection_active() && (XG(remote_connection_pid) != getpid()))) {
xdebug_restart_debugger();
}
return (
XG(remote_connection_enabled) && (XG(remote_connection_pid) == getpid())
);
}
void xdebug_mark_debug_connection_active()
{
XG(remote_connection_enabled) = 1;
XG(remote_connection_pid) = getpid();
}
void xdebug_mark_debug_connection_pending()
{
XG(remote_connection_enabled) = 0;
XG(remote_connection_pid) = 0;
}
void xdebug_mark_debug_connection_not_active()
{
if (XG(remote_connection_enabled)) {
xdebug_close_socket(XG(context).socket);
xdebug_close_log();
}
XG(remote_connection_enabled) = 0;
XG(remote_connection_pid) = 0;
}
void xdebug_do_jit()
{
if (
(XG(remote_mode) == XDEBUG_JIT) &&
!xdebug_is_debug_connection_active_for_current_pid() &&
XG(remote_enable)
) {
xdebug_init_debugger();
}
}
static void xdebug_update_ide_key(char *new_key)
{
if (XG(ide_key)) {
xdfree(XG(ide_key));
}
XG(ide_key) = xdstrdup(new_key);
}
static int xdebug_handle_start_session()
{
int activate_session = 0;
zval *dummy;
/* Set session cookie if requested */
if (
((
(dummy = zend_hash_str_find(Z_ARR(PG(http_globals)[TRACK_VARS_GET]), "XDEBUG_SESSION_START", sizeof("XDEBUG_SESSION_START") - 1)) != NULL
) || (
(dummy = zend_hash_str_find(Z_ARR(PG(http_globals)[TRACK_VARS_POST]), "XDEBUG_SESSION_START", sizeof("XDEBUG_SESSION_START") - 1)) != NULL
))
&& !SG(headers_sent)
) {
convert_to_string_ex(dummy);
xdebug_update_ide_key(Z_STRVAL_P(dummy));
xdebug_setcookie("XDEBUG_SESSION", sizeof("XDEBUG_SESSION") - 1, Z_STRVAL_P(dummy), Z_STRLEN_P(dummy), time(NULL) + XG(remote_cookie_expire_time), "/", 1, NULL, 0, 0, 1, 0);
activate_session = 1;
} else if (
(dummy = zend_hash_str_find(Z_ARR(PG(http_globals)[TRACK_VARS_COOKIE]), "XDEBUG_SESSION", sizeof("XDEBUG_SESSION") - 1)) != NULL
) {
convert_to_string_ex(dummy);
xdebug_update_ide_key(Z_STRVAL_P(dummy));
activate_session = 1;
} else if (getenv("XDEBUG_CONFIG")) {
if (XG(ide_key) && *XG(ide_key) && !SG(headers_sent)) {
xdebug_setcookie("XDEBUG_SESSION", sizeof("XDEBUG_SESSION") - 1, XG(ide_key), strlen(XG(ide_key)), time(NULL) + XG(remote_cookie_expire_time), "/", 1, NULL, 0, 0, 1, 0);
}
activate_session = 1;
}
return activate_session;
}
static void xdebug_handle_stop_session()
{
/* Remove session cookie if requested */
if (
((
zend_hash_str_find(Z_ARR(PG(http_globals)[TRACK_VARS_GET]), "XDEBUG_SESSION_STOP", sizeof("XDEBUG_SESSION_STOP") - 1) != NULL
) || (
zend_hash_str_find(Z_ARR(PG(http_globals)[TRACK_VARS_POST]), "XDEBUG_SESSION_STOP", sizeof("XDEBUG_SESSION_STOP") - 1) != NULL
))
&& !SG(headers_sent)
) {
xdebug_setcookie("XDEBUG_SESSION", sizeof("XDEBUG_SESSION") - 1, (char*) "", 0, time(NULL) + XG(remote_cookie_expire_time), "/", 1, NULL, 0, 0, 1, 0);
}
}
void xdebug_do_req(void)
{
if (XG(remote_mode) != XDEBUG_REQ) {
return;
}
if (
XG(remote_enable) &&
!xdebug_is_debug_connection_active_for_current_pid() &&
(XG(remote_autostart) || xdebug_handle_start_session())
) {
xdebug_init_debugger();
}
xdebug_handle_stop_session();
}
1
https://gitee.com/yanghuangsheng_admin/sdebug.git
git@gitee.com:yanghuangsheng_admin/sdebug.git
yanghuangsheng_admin
sdebug
sdebug
master

搜索帮助