Plugin::getWritableFiles()   A
last analyzed

Complexity

Conditions 3
Paths 3

Size

Total Lines 10
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 12

Importance

Changes 0
Metric Value
cc 3
eloc 6
c 0
b 0
f 0
nc 3
nop 1
dl 0
loc 10
ccs 0
cts 5
cp 0
crap 12
rs 10
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
Bug introduced by
The type Composer\Composer 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. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

filter:
    dependency_paths: ["lib/*"]

For further information see https://scrutinizer-ci.com/docs/tools/php/php-scrutinizer/#list-dependency-paths

Loading history...
38
	 * @param IOInterface $io
0 ignored issues
show
Bug introduced by
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. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

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
Bug introduced by
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. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

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
Bug introduced by
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. excluded_paths: ["lib/*"], you can move it to the dependency path list as follows:

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