@@ -286,6 +286,12 @@ final class EvoBootstrapper
286286 return ;
287287 }
288288
289+ $ home = $ this ->resolveHomeDir ();
290+ $ composerHome = getenv ('COMPOSER_HOME ' );
291+ if (!is_string ($ composerHome ) || trim ($ composerHome ) === '' ) {
292+ $ composerHome = rtrim ($ home , "/ \\" ) . DIRECTORY_SEPARATOR . '.composer ' ;
293+ }
294+
289295 $ this ->out ('Updating PHP installer package via Composer... ' );
290296 $ code = $ this ->runProcess (
291297 [
@@ -299,6 +305,10 @@ final class EvoBootstrapper
299305 $ workDir ,
300306 [
301307 'COMPOSER_ALLOW_SUPERUSER ' => '1 ' ,
308+ // Composer requires either HOME or COMPOSER_HOME.
309+ // Some environments (cron, systemd, restrictive shells) may clear HOME.
310+ 'HOME ' => $ home ,
311+ 'COMPOSER_HOME ' => $ composerHome ,
302312 ]
303313 );
304314 if ($ code !== 0 ) {
@@ -406,6 +416,25 @@ final class EvoBootstrapper
406416 return false ;
407417 }
408418
419+ private function resolveHomeDir (): string
420+ {
421+ $ home = getenv ('HOME ' );
422+ if (is_string ($ home ) && trim ($ home ) !== '' ) {
423+ return $ home ;
424+ }
425+
426+ if (function_exists ('posix_geteuid ' ) && function_exists ('posix_getpwuid ' )) {
427+ $ info = @posix_getpwuid (posix_geteuid ());
428+ if (is_array ($ info ) && isset ($ info ['dir ' ]) && is_string ($ info ['dir ' ]) && trim ($ info ['dir ' ]) !== '' ) {
429+ return $ info ['dir ' ];
430+ }
431+ }
432+
433+ return PHP_OS_FAMILY === 'Windows '
434+ ? (getenv ('USERPROFILE ' ) ?: 'C: \\' )
435+ : '/root ' ;
436+ }
437+
409438 /**
410439 * @param array<int, string> $cmd
411440 * @param array<string, string> $env
@@ -428,6 +457,11 @@ final class EvoBootstrapper
428457 }
429458
430459 // Fallback: execute via shell.
460+ foreach ($ env as $ k => $ v ) {
461+ if (is_string ($ k ) && is_string ($ v )) {
462+ @putenv ($ k . '= ' . $ v );
463+ }
464+ }
431465 $ cmdParts = [];
432466 foreach ($ cmd as $ part ) {
433467 $ cmdParts [] = escapeshellarg ($ part );
0 commit comments