'PhpStorm Xdebug remote ssh debugging of CLI script on Vagrant breakpoints not triggering

I am trying to debug a PHP script which is checked out locally on a Windows machine, then mapped to a Ubuntu VM (configured using Vagrant) which have Nginx, PHP and Xdebug installed. Also it's important to point out that I have php-fpm working in this setup and I have had a PHP script running as well, but in VSCode and not PhpStorm.

My PhpStorm config is:

enter image description here

My Xdebug config (currently, I have tried a million different config now):

zend_extension=xdebug.so
xdebug.mode=debug
xdebug.client_host=127.0.0.1
xdebug.client_port=9003
xdebug.remote_enable=1

I then configure my SSH tunnel like so:

putty.exe -ssh <vm-ip> -R 9003:localhost:9003

I am able to run the file and get its output in PhpStorm, but my breakpoints are not working. I just get the following:

enter image description here enter image description here enter image description here

And this is the content of the php file I am trying to debug:

enter image description here

So as we can see, the script executes without problem, the breakpoints just don't trigger. And as mentioned I have Xdebug working in PhpStorm for php-fpm when debugging websites, but when trying to debug a single PHP script I run into this problem.

I have tried so many different things, which makes me sure I am overlooking something basic I have forgotten. Right now I am suspecting PhpStorm for being annoying.. on output we can see the script is invoked with:

[vagrant://C:\vagrant]:/usr/bin/php -dxdebug.mode=debug -dxdebug.client_port=9002 -dxdebug.client_host=192.168.1.185

I have not entered these -d arguments anywhere and I am not sure why PhpStorm keeps adding them (also it uses port 9002 and I have configured 9003). But I am not able to get anything working in VSCode as well, so I am properly doing something wrong.

My Xdebug config for php-fpm which is currently working in PhpStorm is:

zend_extension=xdebug.so

xdebug.mode=develop,debug
xdebug.idekey=PHPSTORM

xdebug.output_dir=/tmp/xdebug
xdebug.log=/tmp/xdebug/xdebug.log
xdebug.remote_log=/root/logs/xdebug.log

xdebug.force_display_errors=1
xdebug.force_error_reporting=1

xdebug.remote_enable=1
xdebug.remote_handler=dbgp
xdebug.remote_host=127.0.0.1
xdebug.remote_autostart=1

xdebug.client_host=127.0.0.1
xdebug.client_port=9003

xdebug.remote_connect_back=0

xdebug.var_display_max_depth=-1
xdebug.var_display_max_children=-1
xdebug.var_display_max_data=-1

.. i then have a PHP | Servers settings for this as well:

enter image description here

If I try to use this config for PHP CLI script debugging, it's not working either (+ its PhpStorm waiting for Xdebug connections which I guess works a bit differently from PHP CLI script debugging)

What am I doing wrong since my breakpoints are not triggering when running single CLI scripts?



Solution 1:[1]

I found a solution, it stupid but it works..

So essentially what annoyed me a lot, was that PHPSTORM added intepretor arguments which i did not specify, which i also mentioned above in the question.. it ended up executing the following on VM:

[vagrant://C:\vagrant]:/usr/bin/php -dxdebug.mode=debug -dxdebug.client_port=9002 -dxdebug.client_host=192.168.1.185

I did not spoecify these -d arguments and could not for the life of me figure out how to make PHPSTORM remove them.. as mentioned in the question comments the port is specified through settings | php | debug | "debug port" so at least i could change that.. but the client_host was still wrong.

What i did to fix is, is just overriding it again so the cmd executed on the VM ended up being this (obs: i have used a lot of different ports to try and fix it.. which is why i am now using 9004):

[vagrant://C:\vagrant]:/usr/bin/php -dxdebug.mode=debug -dxdebug.client_port=9004 -dxdebug.client_host=192.168.1.185 -dxdebug.client_host=127.0.0.1 thefile-i-wanna-debug.php

My guess is this overrides the first, wrong, argument and then makes everything work. You do this by adding intepretor arguments like so in your run-configuration:

enter image description here

and the xdebug config i ended up with, now matches all the guides i have found on SSH debugging as well, and is only:

zend_extension=xdebug.so
xdebug.idekey=PHPSTORM
xdebug.mode=debug
xdebug.client_host=127.0.0.1
xdebug.client_port=9004

Success! :-D

enter image description here

Solution 2:[2]

The enumerate call returns a tuple on each loop, not a single value. So, your i is being set to a tuple, which consists of the index (starting at 1) and the element in the pointlist. You can fix this many ways. One is to change:

for i in enumerate(pointlist, start=1):

to:

for i in range(len(pointlist), start=1):

Or you can keep the enumerate call and drop the returned element of pointlist, which doesn't really make much sense, but it's an option:

for i, _ in enumerate(pointlist, start=1):

Here, the _ is a placeholder that takes the pointlist value to prevent i from being a tuple. The first option is much better.

Note that list indeces start at 0, not 1, so you're start=1 is probably going to break your logic. You might be much better off with the default start value of 0.

Solution 3:[3]

you might want to use range instead of enumerate.

import random 
X=1350
Y=250

p1=[X, Y]
p2=[X, Y]
p3=[X, Y]
p4=[X, Y]
p5=[X, Y]
p6=[X, Y]
p7=[X, Y]
p8=[X, Y]
p9=[X, Y]
p10=[X, Y]
p11=[X, Y]
pointlist = [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11]

limit1=1150
limit2=1250

for i in range(len(pointlist)):
    pointlist[i][0] = random.randrange(limit1, limit2)
    limit1-=100
    limit2-=100

if you still want to use enumerate.

import random 
X=1350
Y=250

p1=[X, Y]
p2=[X, Y]
p3=[X, Y]
p4=[X, Y]
p5=[X, Y]
p6=[X, Y]
p7=[X, Y]
p8=[X, Y]
p9=[X, Y]
p10=[X, Y]
p11=[X, Y]
pointlist = [p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11]

limit1=1150
limit2=1250

for i in enumerate(pointlist, start=0):
    index = i[0] # get the index from here.
    value = i[1]
    pointlist[index][0] = random.randrange(limit1, limit2)
    limit1-=100
    limit2-=100

Solution 4:[4]

Off-topic.

Adding to Mat's amazing answer:

I believe you explicitly created p1...p11 so when you change the x-coordinate of a point, other points will not be affected. If you are not going to use the references p1...p11, I suggest using a list comprehension:

point_list = [[X, Y] for _ in range(11)]

The inner list [X, Y] is created 11 times, and they are 11 separate objects, so changing any one of it will not affect the others. You can visualise it using Python Tutor.

I personally prefer using custom objects than dealing with nested lists in your case, as it better displays the intent of the code. Here is how I would have coded it:

import random

class Coordinate:
    """
    A container that represents a coordinate point.
    Functions to manipulate the coordinates (called methods)
    can be added here.
    You can optionally convert it to a dataclass using
    functools.dataclass decorator to clean up the code further.
    """

    def __init__(self, x: float, y: float) -> None:
        """ At creation of the Coordinate object,
        we set its x, y-coordinate values. """
        self.x = x
        self.y = y
    
    def __repr__(self) -> str:
        """ Defines how a Coordinate should be represented as a string."""
        return f'Coordinate({self.x}, {self.y})'

X = 1350
Y = 250

coords = [Coordinate(X, Y) for _ in range(11)]

lower_bound = 1150
upper_bound = 1250

for coord in coords:
    # Here we are saying we want to change the x-coordinate,
    # instead of the ambiguous coord[0] = ...
    coord.x = random.randrange(1150, 1250)
    lower_bound -= 100
    upper_bound -= 100

print(coords)

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Thor A. Pedersen
Solution 2 Gary02127
Solution 3
Solution 4 Bill Ong