Welcome to reprint, but please quote the original source at the beginning or end.

preface

At the beginning of the previous PHP debugging guide (Xdebug edition), I said, “Read through this article and no one will know PHP Xdebug better than you.” I didn’t expect to hit the face so fast, this only after three or four days, I found that today I than I wrote before, more understand.

PhpStorm 2020.3 and Xdebug 3

In the previous article, I used PhpStorm 2020.2.4, so when using Web Server Debug Validation with Xdebug 3.0.0 for debugging environment Validation, Error message similar to Xdebug port is invalid is displayed. This error is caused by incompatible version 3.0.0. So I demoted to Xdebug 2.9.8 to finish the article.

PhpStorm 2020.3 was released the day after I wrote the previous article

  • rightPHP 8The support of
  • rightXdebug 3The support of

After reinstalling the PHP 8 + Xdebug 3.0.0 environment with PHPBrew and deploying it with Nginx + php-fPM, The Web Server Debug Validation succeeds.

aboutWeb Server Debug Validationfunction

After writing the above article, I reinstalled PHP 7.4.13 + Xdebug 3.0.0 before upgrading PhpStorm 2020.3. There was no problem when I directly started debugging without ignoring the verification error. Therefore, this function only verifies the debugging environment and is used for reference only before debugging, without affecting actual debugging.

aboutRemote debugging

When I wrote the previous section on remote debugging, I referred to a lot of articles on the Internet. It seems to be thoroughly understood, but in fact it is not, for several reasons:

  • The author of many articles on the Internet also wrote the same as the author wrote the previous article, to the principle of the half-understanding, leading to a lot of explanation is not perfect or contradictory. In: StudyJetBrains / VSCode / XdebugTo understand how it works.
    • Configure Xdebug — PhpStorm PhpStorm
    • Remote debugging via SSH tunnel – PhpStorm PhpStorm official: Remote debugging through SSH tunnel
    • Multiuser debugging via Xdebug proxies — PhpStorm PhpStorm official: Multiple debugging through the Xdebug agent
    • PHP Debug Adapter for Visual Studio Code
    • Step Debugging Xdeubg Official: Single-step Debugging
    • Documentation – All Settings Xdebug official: All configuration items
    • Upgrading Xdebug from Xdebug 2 to Xdebug 3
  • I wrote the previous article when the constructionRemote debugging environmentimperfect
    • This machineRemote serverAre allmacOS
    • This machineRemote serverAll inWithin the local area network (LAN)

IDEIn combination withXdebugPrinciple of Debugging

  • IDE (by itself or with plug-ins)Open local9000Port and listens (Xdebug 2.X defaults to9000, Xdebug 3.X The default value is9003, but can be modified)
  • IDE (by itself or with plug-ins)Do the path mapping (path mappingThat is, the project directory opened locally in the IDE is mapped to the project directory on the remote server, for example
    • MacOS local:/Users/chaos/Work/php/demos/debug/
    • Linux server:/home/chaos/Work/php/demos/debug/
  • When the local sends a request to the serverCookie: XDEBUG_SESSION=IDEKEY
  • The server experienced an error when receiving the requestNginx -> php-fpmAfter the arrivalXdebug.XdebugdetectedXDEBUG_SESSIONcookie, this request is considered to be withDebugging purposesYes, and hang it at the same timeThe PHP interpreterFurther processing the request
  • thenXdebugphp.iniGets the destination address from or$_SERVERTo retrieve the source address of the request (e.g223.104.148.182) as the destination address, and then to the destination address9000Port InitiationDebug connection
  • The localIDE (by itself or with plug-ins)Detected listening9000Port has aDebug connectionEstablish, judgeXDEBUG_SESSIONWhether preset for oneselfIDE key
    • If it’s not presetIDE keyThrough the9000On the portDebug connectionTell the serverXdebug“, “Do not belong to my management, I do not deal with”, and then both sides negotiate to disconnect
    • If it’s defaultIDE keyAt the same time, a breakpoint is set locally or a breakpoint is set locally"stopOnEntry": true (VSCode) / Break at first line in PHP scriptsPhpStorm tells the serverXdebug“, “Roger, ready for debugging”, and then the two sides negotiate to enter the debugging state

In the real worldRemote debuggingtrap

The smart ones may have spotted a pitfall in the debugging process above: That is, the server needs to request the local to establish a debugging connection, but the problem is that now all the home/enterprise network environment, the so-called local router under the NAT, there is no exposed IP address in the public network, so the local 9000 port for the server, is unreachable, want to access, dream!

Fill in the pittrap

The author re-simulates the real debugging environment, that is, macOS is the local and two Linux servers are selected for the remote server, one is the physical machine built by the author in the company, and the other is the aliyun cloud host purchased by the company.

The ultimate purpose of pit filling is to expose the local 9000 port to the server and make it directly reachable.

This points:

  1. Local and remote servers reside on the same LAN, for example, joining the same serverVPNNetwork, local accessVPNAssigned to the serverPrivate IPAccess to the server, server ofXdebugThe source address that is parsed also passesVPNAssigned locallyPrivate IPDirectly accessible.
  2. The router itself comes fromISP (Broadband operator)throughPPPoE dialAccess to thePublic IPAnd then pass through the routerPort mappingThe DMZ mode, will be local9000Port, mapped to the router9000Port so that the server can also pass throughPublic IP: 9000Access to the local9000Port. (This method is most recommended, but feasible in China is not high, because domesticThe IP address poolIt’s going to dry up, so it’s hard to get it from the carrierPublic IP)
  3. Other environments can only be relied uponGraft: with the help ofSSH Reverse TunnelTo create a link between the local and the serverThe TCP channel, will be local9000Port mapped to the server9000Port. In that case, on the serverXdebugaccesslocalhost:9000That’s accessIDE of the local9000Port. (Borrow an illustration from the official JetBrains documentation.)

Here, the author summed up the first two environments as the return network is directly accessible, otherwise it is the return network is not direct.

PhpStormSpecial configuration of

Before listing the specific configuration of remote debugging parameters, I also need to separate out the special configuration of PhpStorm.

PhpStorm debug target Server to Server is configured, the specific Languages in preferences and Frameworks | | PHP Servers. See JetBrains’ official documentation for more details.

On this page, configure HTTP access for debugging engines to interact with local and remote Web servers and set correspondence between files on the server and their local copies in the PhpStorm project.

On this page, configure HTTP access for debugging to interact with local and remote Web servers, and associate files on the remote server with local copy Settings opened in the PhpStorm project.

Special configuration for PhpStorm debugging: add these two lines to the phP-fPM configuration file on the remote server:

clear_env = no
env["PHP_IDE_CONFIG"] = "serverName=UbuntuServer"
Copy the code

Here UbuntuServer is a custom server name that you can change yourself.

Then in PhpStorm preferences of Languages and Frameworks | | PHP Servers to add a Server

  • nameUbuntuServer
  • HostPortThe author can fill in any legal value,PhpStormNot check, so I filled in0
  • DebuggerchooseXdebug
  • Check onUse path mappingsAnd set it upLocal file directory pathServer file directory pathFor example, the author’s local mapping/Users/chaos/Work/php/demos/debug/With the server/home/chaos/Work/php/demos/debug/)

VSCodeThe configuration of the

You only need to configure one more path mapping than native debugging, namely the pathMappings key value pair, along with the contents of the launch.json file:

Configurations ": [{"version": "0.2.0", "Configurations ": [{"name": "Listen for XDebug", "type":" PHP ", "request": "launch", "port": 9000, // "stopOnEntry": true, "pathMappings": { "/home/chaos/Work/php/demos/debug/": "${workspaceRoot}/", } }, { "name": "Launch currently open script", "type": "php", "request": "launch", "program": "${file}", "cwd": "${fileDirname}", "port": 9000 } ] }Copy the code

“/ home/here chaos/Work/PHP/demos/debug/” :” ${workspaceRoot} / “is”/home/chaos/Work/PHP/demos/debug/” : “/ Users/chaos/Work/PHP/demos/debug/” simplified form, ${workspaceRoot} is VSCode opened in the root directory of the project.

The server’sphp.iniConfiguration in different situations

Case 1:The return network is directly accessible

  • Xdebug 2.X
[xdebug]
xdebug.remote_enable=1
xdebug.remote_connect_back=1
Copy the code

| remote_enable = 1 said open remote debugging

| remote_connect_back = 1 said get request launched address (from $_SERVER [‘ HTTP_X_FORWARDED_FOR] and $_SERVER [‘ REMOTE_ADDR] extract), Reverse access to the 9000 port of the originating address to establish a debugging connection

  • Xdebug 3.X
[xdebug]
xdebug.mode=debug
xdebug.discover_client_host=true
xdebug.port=9000
Copy the code

| mode = debug replaced 2 X version remote_enable = 1

| discover_client_host = true to replace the 2 X version of the xdebug. Remote_connect_back = 1

| port = 9000 is a personal preference, in 3. The default is 9003 X. I prefer to be consistent with 2.x, so that the same IDE configuration can be debugged for both 2.x and 3.x versions

Situation 2:The return network is not direct

Map the local 9000 port to the server 9000 port using SSH tunnels

SSH -g-n-r 9000:127.0.0.1:9000 user@serverCopy the code
  • Xdebug 2.X (Method A)
[xdebug] xdebug. Remote_enable = 1 xdebug. Remote_host = 127.0.0.1Copy the code

| remote_host = 127.0.0.1 said directly to 127.0.0.1 debug connection to this address the request

  • Xdebug 2.X (Method B)
[xdebug]
xdebug.remote_enable=1
xdebug.remote_connect_back=1
xdebug.remote_addr_header="HTTP_X_XDEBUG_REMOTE_ADDR"
Copy the code

| remote_connect_back = 1 said get request address, reverse access address debug connection to port 9000

| xdebug. Remote_addr_header = “HTTP_X_XDEBUG_REMOTE_ADDR” said priority from $_SERVER [‘ HTTP_X_XDEBUG_REMOTE_ADDR] get a address, $_SERVER[‘ HTTP_X_FORWARDED_FOR’]; $_SERVER[‘REMOTE_ADDR’]

| debug request is similar to the $curl server.com – 8000 – b XDEBUG_SESSION = IDEKEY -h “X – Xdebug – Remote – Addr: 127.0.0.1”

| note: HTTP – send request need not add, because for custom header, Nginx automatically add prefix.http_, and all caps, dash to underline, deposited in the $_SERVER global variable

  • Xdebug 3.X (Method A)
[xdebug] xdebug. Mode = debug xdebug. Port = 9000 xdebug. Client_host = 127.0.0.1Copy the code

| client_host = 127.0.0.1 said directly tell Xdebug, address is 127.0.0.1, to the address you request debug connections

  • Xdebug 3.X (Method B)
[xdebug]
xdebug.mode=debug
xdebug.port=9000
xdebug.discover_client_host=true
xdebug.client_discovery_header="HTTP_X_XDEBUG_REMOTE_ADDR"
Copy the code

| client_discovery_header = “HTTP_X_XDEBUG_REMOTE_ADDR” replaced the 2 X version of the xdebug. Remote_addr_header = “HTTP_X_XDEBUG_REMOTE_ADDR”


Xdebug 2.x (Method B) is slightly different from Xdebug 3.x (Method B) :

  • Xdebug 2.X (Method B)If the request originating address is not found according to the configuration rules, it is not degraded127.0.0.1 localhost /As the originating address of the request
  • Xdebug 3.X (Method B)If the request originating address is not found according to the configuration rules, it is degraded127.0.0.1 localhost /As the originating address of the request

Multiplayer debugging – DBGp

Attach the reference documents first

  • Multiuser debugging via Xdebug Proxies PhpStorm Official: Perform multiple debugging via DBGp proxies
  • DBGp Proxy Tool Xdebug Official

Not only am I going to skip this one, I’m going to make fun of it. Take a look at an illustration from the above article “Multiuser Debugging via Xdebug Proxies”

It seems wonderful, isn’t it, but after downloading dbgpProxy and experimenting with it repeatedly, I found that the tool is really a magic pit.

I ran it on aliyun/dbgpProxy -i 0.0.0.0:9001 -s 127.0.0.1:9000Post from localPhpStormBring customIDE key "PS"Initiate a debug request and resultdbgpProxyLog printConnecting to 112.3.2.42:9000And the local broadband where the author lives does not have public IP.112.3.2.42This IP is multi-layeredNATThe old IP, of course, can’t get in, only upSSH Tunnel Scheme.

So what’s the point of dbgpProxy? I found an article on the Internet by Derick Rethans, author of Xdebug (who also designed DBGp protocol) – Debugging with Multiple Users. In this article, he described DBDp usage scenarios:

Running a DBGp proxy also allows you to avoid NAT issues where (as seen from PHP+Xdebug on the server) all connections seem to come from the same IP (because your internal network is NATted). In this case, you can simple run the dbgp proxy on your NAT machine, configure xdebug.remote_host setting to the IP address of your NAT machine, and configure the IDEs to connect to the proxy running at :9001.

To paraphrase:

  • Your router has to get a public IP address from an ISP
  • Run it on your routerdbgpProxy
  • For everyone under the routerIDEDBGp Proxy configurationHostEnter the router gateway, that is, the Intranet address of the router

From here, you can find that setting up DBGp debugging environment is very demanding. Combining public IP and router running dbgpProxy, only soft routing can meet the requirements. Because dbgpProxy binary executables are available only in Windows/macOS/Linux x86-64 versions. So most people/companies can go to bed.

conclusion

In order to write these two articles, the author did a lot of experiments, also sorted out a lot of knowledge points, made a lot of drafts (paper drafts in the real sense), and finally attached the most satisfactory one.

I hope you found it interesting, and thanks for reading!