When using PHP inside a Docker container on Windows (e.g. using DDEV), symbolic links that are created inside the container (e.g. by composer) do not seem to work correctly with PHP's file streams.
Imagine the following PHP code
<?php
mkdir('demo-base-directory');
symlink('demo-base-directory', 'demo-symbolic-link');
var_dump(glob('demo-*', GLOB_ONLYDIR));
If executed inside the container, it outputs only demo-base-directory
, however demo-symbolic-link
is missing (the very same example works as expected on Linux/Unix systems inside Docker containers)
array(1) {
[0]=>
string(19) "demo-base-directory"
}
When viewing the symbolic link in the host system (e.g. using cat demo-symbolic-link
in Windows PowerShell) it shows
XSym
0019
0df68e8650ddca993c28277a5cfa3dcd
demo-base-directory
There have been other reports to Docker for Windows about symlink emulation - I could not reproduce this behavior for files using fgets
or file_get_contents
but for the mentioned glob
invocation, see
Shared volumes are mounted in a Linux-based Docker container on a Windows host system as Samba/CIFS mount like this:
//10.0.75.1/C on /var/www/html type cifs (rw,relatime,vers=3.02,sec=ntlmsspi,cache=strict,username=olly,domain=OLIVERHADERB9D8,uid=0,noforceuid,gid=0,noforcegid,addr=10.0.75.1,file_mode=0755,dir_mode=0777,iocharset=utf8,nounix,serverino,mapposix,nobrl,mfsymlinks,noperm,rsize=1048576,wsize=1048576,echo_interval=60,actimeo=1)
Mount option mfsymlinks
refers to Minshall+French symlinks
Instead of creating symbolic links inside the container, creating them outside (directly in Windows) solves the problem.
del demo-symbolic-link
mklink /d demo-symbolic-link demo-base-directory
output
symbolic link created for demo-symbolic-link <<===>> demo-base-directory
del demo-symbolic-link
cmd /c mklink /d demo-symbolic-link demo-base-directory
output
symbolic link created for demo-symbolic-link <<===>> demo-base-directory
side note: New-Item -ItemType SymbolicLink
could not be resolved using glob(..., GLOB_ONLYDIR in PHP
- using mklink /d
here as well
I had to execute the following while executing Git-Bash as administrator. Setting the environment variable with export
is important here - see Enable native NTFS symbolic links for Cygwin
rm demo-symbolic-link
export MSYS=winsymlinks:nativestrict
ln -s demo-base-directory/ demo-symbolic-link
I've created helper tool examples that search for Samba XSym
pointers in a particular directory (TYPO3 related, public/typo3conf/ext/
) and "upgrade" the XSym pointers to proper symlinks - probably admin privileges are required when executing those scripts:
Executing the PHP example from above again now outputs both expected items
array(2) {
[0]=>
string(19) "demo-base-directory"
[1]=>
string(18) "demo-symbolic-link"
}
Working inside a Docker container and having to adjust symbolic links manually on the host system is really just a workaround - not a solution. At which level could this be enhanced and optimized in order to create proper symbolic links using the Docker container only?
It seems this could be resolved at different layers:
glob
invocation (especially for flaky GLOB_ONLYDIR
flag)glob
implementation (especially for Minshall+French symlinks XSym
)Updates
mklink /j
(junction) to mklink /d
(symlinked directory) since removing the linked junction removed it's origin as wellNew-Item -ItemType SymbolicLink
(instead of previous New-Item -ItemType Junction
) then again could not be resolved using glob(..., GLOB_ONLYDIR
in PHP - as a result, using cmd /c mklink /d
hereStarting with ddev v1.5.0, the ddev composer
command on Windows attempts to convert XSym symlinks to legitimate Windows symlinks. This feature only works if you have enabled "Developer mode" on Windows. See Windows OS and ddev composer in docs.