OccRunner::run()   B
last analyzed

Complexity

Conditions 6
Paths 8

Size

Total Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 11
CRAP Score 7.0986

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 23
ccs 11
cts 16
cp 0.6875
rs 8.9297
cc 6
nc 8
nop 3
crap 7.0986
1
<?php
2
/**
3
 * @author Victor Dubiniuk <[email protected]>
4
 *
5
 * @copyright Copyright (c) 2015, ownCloud, Inc.
6
 * @license AGPL-3.0
7
 *
8
 * This code is free software: you can redistribute it and/or modify
9
 * it under the terms of the GNU Affero General Public License, version 3,
10
 * as published by the Free Software Foundation.
11
 *
12
 * This program is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15
 * GNU Affero General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Affero General Public License, version 3,
18
 * along with this program.  If not, see <http://www.gnu.org/licenses/>
19
 *
20
 */
21
22
namespace Owncloud\Updater\Utils;
23
24
use GuzzleHttp\Client;
25
use Owncloud\Updater\Console\Application;
26
use Symfony\Component\Process\Process;
27
use Symfony\Component\Process\ProcessUtils;
28
use Symfony\Component\Process\Exception\ProcessFailedException;
29
30
/**
31
 * Class OccRunner
32
 *
33
 * @package Owncloud\Updater\Utils
34
 */
35
class OccRunner {
36
	/**
37
	 * @var Locator $locator
38
	 */
39
	protected $locator;
40
41
	/**
42
	 * @var bool
43
	 */
44
	protected $canUseProcess;
45
46
	/**
47
	 *
48
	 * @param Locator $locator
49
	 * @param bool $canUseProcess
50
	 */
51 2
	public function __construct(Locator $locator, $canUseProcess){
52 2
		$this->locator = $locator;
53 2
		$this->canUseProcess = $canUseProcess;
54 2
	}
55
56
	/**
57
	 * @param bool $canUseProcess
58
	 */
59
	public function setCanUseProcess($canUseProcess){
60
		$this->canUseProcess = $canUseProcess;
61
	}
62
63
	/**
64
	 * @param $command
65
	 * @param array $args
66
	 * @param bool $asJson
67
	 * @return string
68
	 */
69 2
	public function run($command, $args = [], $asJson = false){
70 2
		if ($this->canUseProcess){
71 1
			$extra = $asJson ? '--output=json' : '';
72 1
			$cmdLine = trim($command . ' ' . $extra);
73 1
			foreach ($args as $optionTitle => $optionValue){
74
				if (strpos($optionTitle, '--') === 0){
75
					$line = trim("$optionTitle=$optionValue");
76
				} else {
77
					$line = $optionValue;
78
				}
79
				$escapedLine = ProcessUtils::escapeArgument($line);
0 ignored issues
show
Deprecated Code introduced by
The method Symfony\Component\Proces...Utils::escapeArgument() has been deprecated with message: since version 3.3, to be removed in 4.0. Use a command line array or give env vars to the `Process::start/run()` method instead.

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
80
				$cmdLine .= " $escapedLine";
81
			}
82 1
			return $this->runAsProcess($cmdLine);
83
		} else {
84 1
			if ($asJson){
85 1
				$args['--output'] = 'json';
86
			}
87 1
			$response = $this->runAsRequest($command, $args);
88 1
			$decodedResponse = json_decode($response, true);
89 1
			return $decodedResponse['response'];
90
		}
91
	}
92
93
	/**
94
	 * @param $command
95
	 * @param array $args
96
	 * @return mixed
97
	 */
98 5
	public function runJson($command, $args = []){
99 5
		$plain = $this->run($command, $args, true);
100
		// trim response to always be a valid json. Capture everything between the first and the last curly brace
101 5
		preg_match_all('!(\{.*\})!ms', $plain, $matches);
102 5
		$clean = isset($matches[1][0]) ? $matches[1][0] : '';
103 5
		$decoded = json_decode($clean, true);
104 5
		if (!is_array($decoded)){
105 1
			throw new \UnexpectedValueException('Could not parse a response for ' . $command . '. Please check if the current shell user can run occ command. Raw output: ' . PHP_EOL . $plain);
106
		}
107 4
		return $decoded;
108
	}
109
110
	/**
111
	 * @param $command
112
	 * @param $args
113
	 * @return string
114
	 */
115
	protected function runAsRequest($command, $args){
116
		$application = $this->getApplication();
117
		$client = new Client();
118
		$endpointBase = $application->getEndpoint();
119
		$params = [
120
			'timeout' => 0,
121
			'json' => [
122
				'token' => $application->getAuthToken(),
123
				'params'=> $args
124
			]
125
		];
126
		
127
		// Skip SSL validation for localhost only as localhost never has a valid cert
128
		if (preg_match('/^https:\/\/localhost\/.*/i', $endpointBase)){
129
			$params['verify'] = false;
130
		}
131
		
132
		$request = $client->createRequest(
133
			'POST',
134
			$endpointBase . $command,
135
			$params
136
		);
137
138
		$response = $client->send($request);
139
		$responseBody = $response->getBody()->getContents();
140
		return $responseBody;
141
	}
142
143
	/**
144
	 * @return mixed
145
	 */
146
	protected function getApplication(){
147
		$container = Application::$container;
148
		$application = $container['application'];
149
		return $application;
150
	}
151
152
	/**
153
	 * @param $cmdLine
154
	 * @return string
155
	 */
156
	protected function runAsProcess($cmdLine){
157
		$occPath = $this->locator->getPathToOccFile();
158
		$cmd = "php $occPath --no-warnings $cmdLine";
159
		$process = new Process($cmd);
160
		$process->setTimeout(null);
161
		$process->run();
162
163
		if (!$process->isSuccessful()){
164
			throw new ProcessFailedException($process);
165
		}
166
		return $process->getOutput();
167
	}
168
}
169