2026/01/08

From Woozle Writes Code
Jump to navigation Jump to search
Thursday, January 8, 2026 (#8)
Wednesday Thursday Friday

This all starts with the fact that PHP native function proc_open()[1] will accept a command-line as either a string or an array – parameter type "string|array". (This is consistent, I guess, with the fact that PHP in CLI mode can only read its own invocation as an array, passed in global variable $argv.)

Since I need to pass commands around a fair amount, and PHP doesn't let you create a new type from a union (like "string|array"), instead of doing the probably-sensible thing and just always handling commands as strings (which is what I had been doing), I came up with the brilliant idea of spending more time than it's probably worth to wrap that concept in a class which could accept the command as either of the two (string or array) and spit it back out as either one. This, of course, requires being able to convert between them...

That was two days ago. By last night, I had in fact written a clade for this purpose. It does at least seem to make things rather clearer and more rigorous, but it's not yet clear whether it can actually be made to work.

Overnight I figured out what the wrinkle is, but I think it's more reflective of underlying issues than it is an indicator of "not-good solution" (...and it's also solvable).

The wrinkle is that command-line escapement can be recursive, due to multiple layers of transmission.

Example: I have an SQL command ("$sql" for short) which needs to be passed to mysql on a remote server via ssh. The $sql string therefore needs to first be wrapped to be sent to mysql:

echo '<sql command>' | mysql <credentials>

- and then that, in turn, has to be wrapped to be sent from the local machine to the remote server:

ssh <user>@<host> "echo '<sql command>' | mysql <credentials>"

(I'm using "wrapped" here to mean "quoted, with any internal quote-marks escaped" (though I think it also works to just escape any space characters, no quotes needed... but that's even harder to read (for debugging purposes)).)

...which means that any structure we want to use to store the values for each piece will need to be a tree...

...which leads to the question of whether the PHP command-line fx() (which generally will accept either an array or a string) would understand this (or any) hierarchy, or if they're just expecting that anything below the top level should be flattened into an escaped string.

...which in turn, to my mind, just underscores the flakiness of using CLI as an API. Like... there should be a way of talking to external programs without having to carefully encode everything...

(But of course if it weren't flaky, almost none of the stuff I'm doing to try to encapsulate CLI as classes in Ferreteria (and especially The Futilities) would be necessary. Among other things, I'm trying to hide the messiness under the hood.)

The tricky part for me then becomes in the string-to-array conversion: I have to allow for the possibility of more than one layer of wrapping, and also do I want to fully unwrap into a tree? It certainly becomes easier to compose commands that way, but it seems unlikely the PHP fx() would understand that format -- so maybe now I'm supporting three formats:

  • string (0 layers),
  • flat array (1 layer)
  • tree-array (>1 layers)

Also, just on a practical note, the multiple layers of quoting-and-escaping make it much more complicated to parse from string-format.

Questions

  • Does proc_open() really only accept a single-layer array?
    • This opens up the deeper question of whether processes which themselves handle commands – like ssh[2] – can only communicate with those commands using CLI syntax.
  • Do operators (like "|") get their own array-entry?

Footnotes

  1. Is that really the only one? I could have sworn there were at least 2 or 3... [research research...] Okay, pcntl_exec() expects arguments as an array, so that's something...
  2. ...or, at least, can handle commands. The point is that this is why they come up in this context.