interserver /
myadmin-plugin-installer
| 1 | <?php |
||
| 2 | /** |
||
| 3 | * Plugins Management |
||
| 4 | * @author Joe Huss <[email protected]> |
||
| 5 | * @copyright 2019 |
||
| 6 | * @package MyAdmin |
||
| 7 | * @category Plugins |
||
| 8 | */ |
||
| 9 | |||
| 10 | /** |
||
| 11 | * MyAdmin Installer Plugin |
||
| 12 | * @link https://github.com/composer/composer/blob/master/src/Composer/Plugin/PluginInterface.php |
||
| 13 | */ |
||
| 14 | |||
| 15 | namespace MyAdmin\Plugins; |
||
| 16 | |||
| 17 | use Composer\Composer; |
||
| 18 | use Composer\EventDispatcher\EventSubscriberInterface; |
||
| 19 | use Composer\IO\IOInterface; |
||
| 20 | use Composer\Plugin\PluginInterface; |
||
| 21 | use Composer\Plugin\Capable; |
||
| 22 | use Composer\Plugin\PluginEvents; |
||
| 23 | use Composer\Plugin\PreFileDownloadEvent; |
||
| 24 | use Composer\Script\Event; |
||
| 25 | |||
| 26 | /** |
||
| 27 | * MyAdmin Installer Plugin |
||
| 28 | */ |
||
| 29 | class Plugin implements PluginInterface, EventSubscriberInterface, Capable |
||
| 30 | { |
||
| 31 | protected $composer; |
||
| 32 | protected $io; |
||
| 33 | |||
| 34 | /** |
||
| 35 | * Apply plugin modifications to Composer |
||
| 36 | * |
||
| 37 | * @param Composer $composer |
||
|
0 ignored issues
–
show
|
|||
| 38 | * @param IOInterface $io |
||
|
0 ignored issues
–
show
The type
Composer\IO\IOInterface was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||
| 39 | */ |
||
| 40 | public function activate(Composer $composer, IOInterface $io) |
||
| 41 | { |
||
| 42 | $this->composer = $composer; |
||
| 43 | $this->io = $io; |
||
| 44 | //print 'Hello peoples...'; |
||
| 45 | $installer = new Installer($this->io, $this->composer); |
||
| 46 | $this->composer->getInstallationManager()->addInstaller($installer); |
||
| 47 | } |
||
| 48 | |||
| 49 | /** |
||
| 50 | * @return array |
||
| 51 | */ |
||
| 52 | public function getCapabilities() |
||
| 53 | { |
||
| 54 | return [ |
||
| 55 | 'Composer\Plugin\Capability\CommandProvider' => 'MyAdmin\Plugins\CommandProvider' |
||
| 56 | ]; |
||
| 57 | } |
||
| 58 | |||
| 59 | /** |
||
| 60 | * |
||
| 61 | * Events |
||
| 62 | * |
||
| 63 | * Command Events Composer\Script\Event |
||
| 64 | * |
||
| 65 | * pre-install-cmd occurs before the install command is executed with a lock file present. |
||
| 66 | * post-install-cmd occurs after the install command has been executed with a lock file present. |
||
| 67 | * pre-update-cmd occurs before the update command is executed, or before the install command is executed without a lock file present. |
||
| 68 | * post-update-cmd occurs after the update command has been executed, or after the install command has been executed without a lock file present. |
||
| 69 | * post-status-cmd occurs after the status command has been executed. |
||
| 70 | * pre-archive-cmd occurs before the archive command is executed. |
||
| 71 | * post-archive-cmd occurs after the archive command has been executed. |
||
| 72 | * pre-autoload-dump occurs before the autoloader is dumped, either during install/update, or via the dump-autoload command. |
||
| 73 | * post-autoload-dump occurs after the autoloader has been dumped, either during install/update, or via the dump-autoload command. |
||
| 74 | * post-root-package-install occurs after the root package has been installed, during the create-project command. |
||
| 75 | * post-create-project-cmd occurs after the create-project command has been executed. |
||
| 76 | * |
||
| 77 | * Installer Events Composer\Installer\InstallerEvent |
||
| 78 | * |
||
| 79 | * pre-dependencies-solving occurs before the dependencies are resolved. |
||
| 80 | * post-dependencies-solving occurs after the dependencies have been resolved. |
||
| 81 | * |
||
| 82 | * Package Events Composer\Installer\PackageEvent |
||
| 83 | * |
||
| 84 | * pre-package-install occurs before a package is installed. |
||
| 85 | * post-package-install occurs after a package has been installed. |
||
| 86 | * pre-package-update occurs before a package is updated. |
||
| 87 | * post-package-update occurs after a package has been updated. |
||
| 88 | * pre-package-uninstall occurs before a package is uninstalled. |
||
| 89 | * post-package-uninstall occurs after a package has been uninstalled. |
||
| 90 | * |
||
| 91 | * Plugin Events Composer\Plugin\PluginEvents |
||
| 92 | * |
||
| 93 | * init occurs after a Composer instance is done being initialized. |
||
| 94 | * command occurs before any Composer Command is executed on the CLI. It provides you with access to the input and output objects of the program. |
||
| 95 | * pre-file-download occurs before files are downloaded and allows you to manipulate the RemoteFilesystem object prior to downloading files based on the URL to be downloaded. |
||
| 96 | */ |
||
| 97 | public static function getSubscribedEvents() |
||
| 98 | { |
||
| 99 | return [ |
||
| 100 | PluginEvents::PRE_FILE_DOWNLOAD => [ |
||
| 101 | ['onPreFileDownload', 0] |
||
| 102 | ] |
||
| 103 | ]; |
||
| 104 | } |
||
| 105 | |||
| 106 | /** |
||
| 107 | * @param PreFileDownloadEvent $event |
||
|
0 ignored issues
–
show
The type
Composer\Plugin\PreFileDownloadEvent was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||
| 108 | */ |
||
| 109 | public function onPreFileDownload(PreFileDownloadEvent $event) |
||
| 110 | { |
||
| 111 | /*$protocol = parse_url($event->getProcessedUrl(), PHP_URL_SCHEME); |
||
| 112 | if ($protocol === 's3') { |
||
| 113 | $awsClient = new AwsClient($this->io, $this->composer->getConfig()); |
||
| 114 | $s3RemoteFilesystem = new S3RemoteFilesystem($this->io, $event->getRemoteFilesystem()->getOptions(), $awsClient); |
||
| 115 | $event->setRemoteFilesystem($s3RemoteFilesystem); |
||
| 116 | }*/ |
||
| 117 | } |
||
| 118 | |||
| 119 | /** |
||
| 120 | * An event that triggers setting writable permissions on any directories specified in the writable-dirs composer extra options |
||
| 121 | * |
||
| 122 | * @param Event $event |
||
|
0 ignored issues
–
show
The type
Composer\Script\Event was not found. Maybe you did not declare it correctly or list all dependencies?
The issue could also be caused by a filter entry in the build configuration.
If the path has been excluded in your configuration, e.g. filter:
dependency_paths: ["lib/*"]
For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths Loading history...
|
|||
| 123 | * @return void |
||
| 124 | */ |
||
| 125 | public static function setPermissions(Event $event) |
||
| 126 | { |
||
| 127 | if ('WIN' === strtoupper(substr(PHP_OS, 0, 3))) { |
||
| 128 | $event->getIO()->write('<info>No permissions setup is required on Windows.</info>'); |
||
| 129 | return; |
||
| 130 | } |
||
| 131 | $event->getIO()->write('Setting up permissions.'); |
||
| 132 | /* try { |
||
| 133 | self::setPermissionsSetfacl($event); |
||
| 134 | return; |
||
| 135 | } catch (\Exception $setfaclException) { |
||
| 136 | $event->getIO()->write(sprintf('<error>%s</error>', $setfaclException->getMessage())); |
||
| 137 | $event->getIO()->write('<info>Trying chmod...</info>'); |
||
| 138 | }*/ |
||
| 139 | try { |
||
| 140 | self::setPermissionsChmod($event); |
||
| 141 | return; |
||
| 142 | } catch (\Exception $chmodException) { |
||
| 143 | $event->getIO()->write(sprintf('<error>%s</error>', $chmodException->getMessage())); |
||
| 144 | } |
||
| 145 | } |
||
| 146 | |||
| 147 | /** |
||
| 148 | * returns a list of writeable directories specified in the writeable-dirs composer extra options |
||
| 149 | * |
||
| 150 | * @param Event $event |
||
| 151 | * @return array an array of directory paths |
||
| 152 | */ |
||
| 153 | public static function getWritableDirs(Event $event) |
||
| 154 | { |
||
| 155 | $configuration = $event->getComposer()->getPackage()->getExtra(); |
||
| 156 | if (!isset($configuration['writable-dirs'])) { |
||
| 157 | throw new \Exception('The writable-dirs must be specified in composer arbitrary extra data.'); |
||
| 158 | } |
||
| 159 | if (!is_array($configuration['writable-dirs'])) { |
||
| 160 | throw new \Exception('The writable-dirs must be an array.'); |
||
| 161 | } |
||
| 162 | return $configuration['writable-dirs']; |
||
| 163 | } |
||
| 164 | |||
| 165 | /** |
||
| 166 | * returns a list of writeable files specified in the writeable-files composer extra options |
||
| 167 | * |
||
| 168 | * @param Event $event |
||
| 169 | * @return array an array of file paths |
||
| 170 | */ |
||
| 171 | public static function getWritableFiles(Event $event) |
||
| 172 | { |
||
| 173 | $configuration = $event->getComposer()->getPackage()->getExtra(); |
||
| 174 | if (!isset($configuration['writable-files'])) { |
||
| 175 | throw new \Exception('The writable-files must be specified in composer arbitrary extra data.'); |
||
| 176 | } |
||
| 177 | if (!is_array($configuration['writable-files'])) { |
||
| 178 | throw new \Exception('The writable-files must be an array.'); |
||
| 179 | } |
||
| 180 | return $configuration['writable-files']; |
||
| 181 | } |
||
| 182 | |||
| 183 | /** |
||
| 184 | * Sets Writrable Directory permissions for any directories listed in the writeable-dirs option using setfacl |
||
| 185 | * |
||
| 186 | * @param Event $event |
||
| 187 | */ |
||
| 188 | public static function setPermissionsSetfacl(Event $event) |
||
| 189 | { |
||
| 190 | $http_user = self::getHttpdUser($event); |
||
| 191 | foreach (self::getWritableDirs($event) as $path) { |
||
| 192 | self::SetfaclPermissionsSetter($event, $http_user, $path); |
||
| 193 | } |
||
| 194 | foreach (self::getWritableFiles($event) as $path) { |
||
| 195 | self::ChmodPermissionsSetter($event, $http_user, $path, 'file'); |
||
| 196 | } |
||
| 197 | } |
||
| 198 | |||
| 199 | /** |
||
| 200 | * Sets Writrable Directory permissions for any directories listed in the writeable-dirs option using chmod |
||
| 201 | * |
||
| 202 | * @param Event $event |
||
| 203 | */ |
||
| 204 | public static function setPermissionsChmod(Event $event) |
||
| 205 | { |
||
| 206 | $http_user = self::getHttpdUser($event); |
||
| 207 | foreach (self::getWritableDirs($event) as $path) { |
||
| 208 | self::ChmodPermissionsSetter($event, $http_user, $path, 'dir'); |
||
| 209 | } |
||
| 210 | foreach (self::getWritableFiles($event) as $path) { |
||
| 211 | self::ChmodPermissionsSetter($event, $http_user, $path, 'file'); |
||
| 212 | } |
||
| 213 | } |
||
| 214 | |||
| 215 | /** |
||
| 216 | * returns the user the webserver is running as |
||
| 217 | * |
||
| 218 | * @param Event $event |
||
| 219 | * @return string the webserver username |
||
| 220 | */ |
||
| 221 | public static function getHttpdUser(Event $event) |
||
| 222 | { |
||
| 223 | $ps = self::runProcess($event, 'ps aux'); |
||
| 224 | preg_match_all('/^.*([a]pache|[h]ttpd|[_]www|[w]ww-data|[n]ginx)$/m', $ps, $matches); |
||
| 225 | foreach ($matches[0] as $match) { |
||
| 226 | $user = substr($match, 0, strpos($match, ' ')); |
||
| 227 | if ($user != 'root') { |
||
| 228 | return $user; |
||
| 229 | } |
||
| 230 | } |
||
| 231 | } |
||
| 232 | |||
| 233 | /** |
||
| 234 | * sets the needed permissions for the $http_user and the running user on $path using setfacl |
||
| 235 | * |
||
| 236 | * @param Event $event |
||
| 237 | * @param string $http_user the webserver username |
||
| 238 | * @param string $path the directory to set permissions on |
||
| 239 | */ |
||
| 240 | public static function SetfaclPermissionsSetter(Event $event, $http_user, $path) |
||
| 241 | { |
||
| 242 | self::EnsureDirExists($event, $path); |
||
| 243 | self::runProcess($event, 'setfacl -m u:"'.$http_user.'":rwX -m u:'.$_SERVER['USER'].':rwX '.$path); |
||
| 244 | self::runProcess($event, 'setfacl -d -m u:"'.$http_user.'":rwX -m u:'.$_SERVER['USER'].':rwX '.$path); |
||
| 245 | } |
||
| 246 | |||
| 247 | /** |
||
| 248 | * sets the needed permissions for the $http_user and the running user on $path using chmod |
||
| 249 | * |
||
| 250 | * @param Event $event |
||
| 251 | * @param string $http_user the webserver username |
||
| 252 | * @param string $path the directory to set permissions on |
||
| 253 | * @param string $type optional type of entry, defaults to dir, can be dir or file |
||
| 254 | */ |
||
| 255 | public static function ChmodPermissionsSetter(Event $event, $http_user, $path, $type = 'dir') |
||
| 256 | { |
||
| 257 | if ($type == 'dir') { |
||
| 258 | self::EnsureDirExists($event, $path); |
||
| 259 | // self::runProcess($event, 'chmod +a "'.$http_user.' allow delete,write,append,file_inherit,directory_inherit" '.$path); |
||
| 260 | // self::runProcess($event, 'chmod +a "'.$_SERVER['USER'].' allow delete,write,append,file_inherit,directory_inherit" '.$path); |
||
| 261 | } else { |
||
| 262 | self::EnsureFileExists($event, $path); |
||
| 263 | } |
||
| 264 | self::runProcess($event, 'chmod 777 '.$path); |
||
| 265 | self::runProcess($event, 'chown '.$_SERVER['USER'].'.'.$http_user.' '.$path); |
||
| 266 | } |
||
| 267 | |||
| 268 | /** |
||
| 269 | * checks if the given directory exists and if not tries to create it. |
||
| 270 | * |
||
| 271 | * @param Event $event |
||
| 272 | * @param string $path the directory |
||
| 273 | * @throws \Exception |
||
| 274 | */ |
||
| 275 | public static function EnsureDirExists(Event $event, $path) |
||
| 276 | { |
||
| 277 | if (!is_dir($path)) { |
||
| 278 | mkdir($path, 0777, true); |
||
| 279 | if (!is_dir($path)) { |
||
| 280 | throw new \Exception('Path Not Found: '.$path); |
||
| 281 | } |
||
| 282 | if ($event->getIO()->isVerbose() === true) { |
||
| 283 | $event->getIO()->write(sprintf('Created Directory <info>%s</info>', $path)); |
||
| 284 | } |
||
| 285 | } |
||
| 286 | } |
||
| 287 | |||
| 288 | /** |
||
| 289 | * checks if the given file exists and if not tries to create it. |
||
| 290 | * |
||
| 291 | * @param Event $event |
||
| 292 | * @param string $path the directory |
||
| 293 | * @throws \Exception |
||
| 294 | */ |
||
| 295 | public static function EnsureFileExists(Event $event, $path) |
||
| 296 | { |
||
| 297 | if (!is_dir(dirname($path))) { |
||
| 298 | mkdir(dirname($path), 0777, true); |
||
| 299 | touch($path); |
||
| 300 | if (!file_exists($path)) { |
||
| 301 | throw new \Exception('File Not Found: '.$path); |
||
| 302 | } |
||
| 303 | if ($event->getIO()->isVerbose() === true) { |
||
| 304 | $event->getIO()->write(sprintf('Created File <info>%s</info>', $path)); |
||
| 305 | } |
||
| 306 | } |
||
| 307 | } |
||
| 308 | |||
| 309 | /** |
||
| 310 | * runs a command process returning the output and checking return code |
||
| 311 | * |
||
| 312 | * @param Event $event |
||
| 313 | * @param string $commandline the command line to run |
||
| 314 | * @return string the output |
||
| 315 | * @throws \Exception |
||
| 316 | */ |
||
| 317 | public static function runProcess(Event $event, $commandline) |
||
| 318 | { |
||
| 319 | if ($event->getIO()->isVerbose() === true) { |
||
| 320 | $event->getIO()->write(sprintf('Running <info>%s</info>', $commandline)); |
||
| 321 | } |
||
| 322 | exec($commandline, $output, $return); |
||
| 323 | if ($return != 0) { |
||
| 324 | throw new \Exception('Returned Error Code '.$return); |
||
| 325 | } |
||
| 326 | return implode(PHP_EOL, $output); |
||
| 327 | } |
||
| 328 | } |
||
| 329 |
The issue could also be caused by a filter entry in the build configuration. If the path has been excluded in your configuration, e.g.
excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths