Last active
July 4, 2020 13:20
-
-
Save johnstevenson/1236ffc261b2156bbd9c9e7f2059ca68 to your computer and use it in GitHub Desktop.
Composer self-update as admin
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* This demo shows a method for elevating to an Admin on Windows and running | |
* a command in cmd.exe, from a PHP script. It demonstrates how Composer can | |
* self-update to an Admin location. | |
* | |
* Note that it creates composer-phar.txt file in the current directory. | |
*/ | |
$localFilename = ''; // the location where composer.phar is to be installed | |
$newFilename = ''; // the location of the downloaded (or rollback) composer.phar | |
$interactive = true; // assume we are interactive | |
echo "Upgrading to version '3.0.0' (stable channel).", PHP_EOL; | |
// Assume rename($newFilename, $localFilename) fails | |
if (!$interactive) { | |
return 1; | |
} | |
$cygwin = preg_match('/cygwin/i', php_uname()); | |
if (!$cygwin && !defined('PHP_WINDOWS_VERSION_BUILD')) { | |
return 1; | |
} | |
// See if we are already an admin | |
exec('cmd.exe /c fltmc.exe filters', $output, $exitCode); | |
if ($exitCode === 0) { | |
return 1; | |
} | |
// Set up dummy files | |
$localFilename = __DIR__.DIRECTORY_SEPARATOR.'composer-phar.txt'; | |
$newFilename = @tempnam(sys_get_temp_dir(), ''); | |
file_put_contents($newFilename, sprintf('composer phar content %s', microtime())); | |
echo sprintf('Unable to write to the "%s" directory. Access is denied.', dirname($localFilename)), PHP_EOL; | |
$question = ' Complete this operation with Administrator priviledges [yes]? '; | |
$answer = readline($question); | |
$cancelledMsg = 'Operation cancelled. Please run the self-update command as an Administrator.'.PHP_EOL; | |
if (!preg_match('/^y/i', $answer)) { | |
echo $cancelledMsg; | |
return 1; | |
} | |
$hashFunc = function($filename) { | |
return file_exists($filename) ? hash_file('sha3-384', $filename) : ''; | |
}; | |
$newFilenameHash = $hashFunc($newFilename); | |
$tmpFile = @tempnam(sys_get_temp_dir(), ''); | |
$script = $tmpFile.'.ps1'; | |
rename($tmpFile, $script); | |
// Format the file names for cmd.exe | |
if ($cygwin) { | |
$cygwinLocalFilename = $localFilename; | |
$localFilename = exec(sprintf("cygpath -w '%s'", $localFilename)); | |
$newFilename = exec(sprintf("cygpath -w '%s'", $newFilename)); | |
} else { | |
// cmd.exe move seems to be fussy about backslashes | |
$localFilename = str_replace('/', '\\', $localFilename); | |
$newFilename = str_replace('/', '\\', $newFilename); | |
} | |
$ps1 = <<<EOT | |
\$exitCode = 0 | |
try { | |
# Use an elevated cmd.exe to move new filename to local filename | |
Start-Process -FilePath "\$env:comspec" -ArgumentList "/c move /y `"$newFilename`" `"$localFilename`"" -Verb RunAs -WindowStyle Hidden | |
} catch { | |
\$exitCode = 2 | |
} | |
exit \$exitCode | |
EOT; | |
file_put_contents($script, $ps1); | |
if ($cygwin) { | |
$winPath = exec(sprintf("cygpath -w '%s'", $tmpFile)); | |
$script = $winPath.'.ps1'; | |
} | |
$output = null; | |
$command = sprintf('powershell.exe -ExecutionPolicy Bypass -WindowStyle Hidden -File "%s"', $script); | |
exec($command, $output, $exitCode); | |
@unlink($script); | |
if ($exitCode === 0) { | |
// see if the file was moved | |
usleep(300000); | |
$localFilename = $cygwin ? $cygwinLocalFilename : $localFilename; | |
$hash = $hashFunc($localFilename); | |
if ($hash && $hash === $newFilenameHash) { | |
echo 'Operation succeeded.'.PHP_EOL; | |
return 0; | |
} else { | |
echo 'Operation failed (file not written). Please run the self-update command as an Administrator.'.PHP_EOL; | |
return 1; | |
} | |
} elseif ($exitCode === 2) { | |
echo $cancelledMsg; | |
return 1; | |
} else { | |
echo 'Operation failed (unabled to run Powershell script). Please run the self-update command as an Administrator.'.PHP_EOL; | |
if ($output) { | |
echo 'Error: ', implode(PHP_EOL, $output), PHP_EOL; | |
} | |
return 1; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment