Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 87
0.00% covered (danger)
0.00%
0 / 1
CRAP
n/a
0 / 0
getService
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
6
1<?php
2
3/*
4 * This program is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU General Public License
6 * as published by the Free Software Foundation; under version 2
7 * of the License (non-upgradable).
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program; if not, write to the Free Software
16 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
17 *
18 * Copyright (c) 2002-2008 (original work) Public Research Centre Henri Tudor & University of Luxembourg
19 *                         (under the project TAO & TAO2);
20 *               2008-2010 (update and modification) Deutsche Institut für Internationale Pädagogische Forschung
21 *                         (under the project TAO-TRANSFER);
22 *               2009-2012 (update and modification) Public Research Centre Henri Tudor
23 *                         (under the project TAO-SUSTAIN & TAO-DEV);
24 *
25 */
26
27/**
28 * This file contains the TAO Install REST API.
29 *
30 * It provides services aiming at checking the current configuration
31 * of the web serser hosting the API. The following services are implemented.
32 *
33 * The service to be called is indicated by the top-level 'type' attribute of the
34 * sent JSON data structure. It must contain the name of one of the services
35 * described below.
36 *
37 * If a server-side error occurs, a 500 like HTTP status code will be returned with
38 * an approriate message in the response body.
39 *
40 * If the service cannot be chosen from the top-level 'type' attribute, a 404 HTTP
41 * status code will be returned with an approriate message in the response body.
42 *
43 *
44 * CheckPHPConfig (POST)
45 * ---------------------
46 * Inspects the request body to find JSON encoded data that represents
47 * a collection of PHP configuration checks.
48 *
49 * It takes as input a collection of JSON data structures used in the following
50 * web services of this API: CheckPHPRuntime, CheckPHPINIValue, CheckPHPExtension,
51 * CheckFileSystemComponent. It returns a JSON data structure containing a type
52 * equals to 'ReportCollection' with a value attribute containing a collection
53 * of reports that are usually used in the list of services seen above.
54 *
55 *
56 *
57 * Example of call:
58 * {"type": "CheckPHPConfig",
59 *  "value": [{"type": "CheckPHPExtension", "value": {"name": "gd", "optional": false}},
60 *           {"type": "CheckPHPExtension", "value": {"name": "curle", "optional": false}}]}
61 *
62 * will return:
63 * {
64 *     "type": "ReportCollection",
65 *     "value": {
66 *         "type": "PHPExtensionReport",
67 *         "value": {"status": "valid", "message": "PHP Extension 'gd' is loaded.", "optional": false, "name": "gd"}
68 *     },
69 *     {
70 *         "type": "PHPExtensionReport",
71 *         "value": {
72 *             "status": "unknown",
73 *             "message": "PHP Extension 'curle' could not be found.",
74 *             "optional": false,
75 *             "name": "curle"
76 *         }
77 *     }
78 * }
79 *
80 *
81 * CheckPHPExtension (POST)
82 * ------------------------
83 * Inspects the resquest body to find a JSON encoded data that represents
84 * a PHP extension check. With this service, you can know if a PHP Extension is
85 * installed or not on the server-side.
86 *
87 * Example of call:
88 * {"type": "CheckPHPExtension", value": {"name": "gd","optional":false}}
89 *
90 * will return:
91 * {"type":"PHPExtensionReport",
92 *  "value":{"status":"valid","message":"PHP Extension 'gd' is loaded.","optional":false,"name":"gd"}}
93 *
94 * + The value->status attribute contains 'valid' if the extension is loaded or 'unknown' if the extension is
95 * not loaded.
96 *
97 *
98 * CheckPHPDatabaseDriver (POST)
99 * ------------------------
100 * Inspects the resquest body to find a JSON encoded data that represents
101 * a PHP Database Driver check. With this service, you can know if a PHP Database Driver is
102 * installed or not on the server-side.
103 *
104 * Example of call:
105 * {"type": "CheckPHPDatabaseDriver", value": {"name": "mysqli","optional":true}}
106 *
107 * will return:
108 * {"type":"PHPDatabaseDriverReport",
109 *  "value":{"status":"valid","message":"Database Driver 'mysql' is available.","optional":true,"name":"mysql"}}
110 *
111 * + The value->status attribute contains 'valid' if the db driver is loaded or 'unknown' if the dbdriver is
112 * not loaded.
113 *
114 *
115 * CheckPHPINIValue (POST)
116 * -----------------------
117 * Inspects the request body to find a JSON encoded data structure that represents
118 * a PHP INI value check. By calling this service, you are able to known if a PHP INI value
119 * as the execpted value on the server-side.
120 *
121 * Example of call:
122 * {"type": "CheckPHPINIValue",
123 *  "value": {"name": "short_open_tag", "value": "0", "optional":false}}
124 *
125 * will return:
126 * {"type":"PHPINIValueReport",
127 *  "value":{"status":"invalid",
128 *           "message":"PHP Configuration Option 'short_open_tag' = '1' has an unexpected value.",
129 *           "expectedValue":"0",
130 *           "value":"1",
131 *           "name":"short_open_tag",
132 *           "optional":false}}
133 *
134 * + The value->value attribute must be a string.
135 * + The value->status attribute contains 'valid' if the expected PHP INI value is found, 'invalid' if it is not found
136 * and 'unknown' if no value can be retrieved for requested PHP INI Variable.
137 *
138 *
139 * CheckPHPRuntime (POST)
140 * ----------------------
141 * Takes a JSON encoded data structure as input and use it to check
142 * if the PHP runtime exists and is between a min and max PHP standardized version number.
143 *
144 * Example of call:
145 * {"type": "CheckPHPRuntime",
146 *  "value": {"min": "5.3.2", "max": "5.3.9", "optional":false}}
147 *
148 * will return:
149 * {"type":"PHPRuntimeReport",
150 *  "value":{"status":"valid",
151 *  "message":"PHP Version (5.3.9) is between 5.3.2 and 5.3.9.",
152 *  "min":"5.3.2","value":"5.3.9",
153 *  "max":"5.3.9"}}
154 *
155 * + The value->status will be 'valid' if the PHP Runtime version is between value->min and value->max, 'invalid' in any
156 * other case.
157 * + The value->min attribute is not mandatory if the value->max attribute is set. In this case, there is no minimal
158 *   version.
159 * + The value->max attribute is not mandatory if the value->min attribute is set. In this case, theire is no maximal
160 *   version.
161 *
162 *
163 * CheckFileSystemComponent (POST)
164 * -------------------------------
165 * Will look for a JSON encoded data structure as input in the request body. It will
166 * use this information to check if a TAO file system component (file or directory) exists
167 * and has the correct system rights (read|write|execute).
168 *
169 * Example of call:
170 * {"type": "CheckFileSystemComponent",
171 * "value": {"location": "tao/install", "rights": "rw", "optional": true, "name": "tao_install_directory"}}
172 *
173 * + The value->rights attribute contains a string were 'r' states that the file/directory must be readable,
174 * 'w' states that the file/directory must writable and 'x' states that the file/directory must be
175 * executable.
176 * + The value->location attribute is a relative path from the TAO root directory on your web server to
177 * the file you want to test existence and rights.
178 * + The value->name attribute is just there for client convenience to distinguish about which file/directory
179 * is the result.
180 *
181 * will return:
182 * {"type":"FileSystemComponentReport",
183 *  "value":["status": "valid",
184 *           "message": "File system component 'tao_install_directory' is compliant with expected rights (rw).'",
185 *           "name": "tao_install_directory",
186 *           "optional": true,
187 *           "isReadable": true,
188 *           "isWritable": true,
189 *           "isExecutable": false]}
190 *
191 * + The value->status attribute will be 'valid' if the file/directory exists and the expected rights are correct.
192 * + The value->status attribute will be 'invalid' if the file/directory exists but the expected rights are incorrect.
193 * + The value->status attribute will be 'unknown' if the file/directory does not exist or is not accessible with the
194 *   rights
195 * of the hosts has.
196 *
197 *
198 * CheckCustom (POST)
199 * ----------------------
200 * Takes a JSON encoded data structure as input and use it to run a custom
201 * check for a particular extension.
202 *
203 * Example of call:
204 * {"type": "CheckCustom","value": {"name": "ModRewrite", "extension" : "tao", "optional": true}}
205 *
206 * will return:
207 * {"type": "CheckCustomReport",
208 *  "value":{"status": "valid",
209 *           "message":"Apache mod_rewrite is enabled.",
210 *           "name":"ModRewrite",
211 *           "extension":"tao",
212 *           "optional":true}}
213 *
214 * + The value->status value depends on the implementation of the requested check.
215 *
216 *
217 * CheckDatabaseConnection (POST)
218 * ----------------------------------
219 * Takes a JSON data structure as input and use it to run a Database Connection Check
220 * against a particular host, driver, user, password.
221 *
222 * Example of call:
223 * {"type": "CheckDatabaseConnection",
224 *  "value": {"driver": "mysql",
225 *            "user": "root",
226 *            "password": "",
227 *            "host": "localhost",
228 *            "optional": false,
229 *            "overwrite": true,
230 *            "database": "db1",
231 *            "name": "db_connection"}}
232 *
233 * will return:
234 * {"type": "DatabaseConnectionReport",
235 *  "value": {"status": "valid",
236 *            "message": "Database connection successfully established with driver 'mysql'.",
237 *            "optional": false,
238 *            "name": "db_connection"}}
239 */
240
241// phpcs:disable PSR1.Files.SideEffects
242
243use oat\tao\install\api\NotAllowedAPICallException;
244
245// use unicode.
246header('Content-Type:text/html; charset=UTF-8');
247
248// clear sessions.
249session_start();
250session_destroy();
251
252// initialize what we need.
253require_once('init.php');
254
255/**
256 * @param string $rawInput
257 * @param string $serviceName
258 * @return tao_install_services_Service
259 * @throws Exception
260 */
261function getService($rawInput, $serviceName)
262{
263    $data = new tao_install_services_Data($rawInput);
264    $className = "tao_install_services_{$serviceName}Service";
265    if (!class_exists($className)) {
266        throw new Exception("Service does not exist.");
267    }
268
269    return new $className($data);
270}
271
272try {
273    // Deal with the 'CheckProtocol' service first.
274    if ($_SERVER['REQUEST_METHOD'] == 'GET' && $_GET['type'] == 'Sync') {
275        $data = new tao_install_services_Data(['type' => 'Sync']);
276        $service = new tao_install_services_SyncService($data);
277
278        // Execute service.
279        $service->execute();
280        $result = $service->getResult();
281        $contentType = $result->getMimeType();
282        $charset = $result->getEncoding();
283        header("Content-Type:${contentType}; charset=${charset}", 200);
284        echo $result->getContent();
285        die();
286    }
287
288    $service = null;
289    $data = null;
290    if ($_SERVER['REQUEST_METHOD'] == 'GET') {
291        $input = $_GET;
292    } else {
293        $rawInput = file_get_contents('php://input');
294        $input = @json_decode($rawInput, true);
295    }
296
297    if ($input == null) {
298        throw new tao_install_api_MalformedRequestBodyException("Unable to parse request body as valid JSON.");
299    } elseif (!isset($input['type']) || empty($input['type'])) {
300        throw new tao_install_api_InvalidAPICallException("No 'type' attribute found in request body.");
301    } else {
302        if ($_SERVER['REQUEST_METHOD'] == 'GET') {
303            switch ($input['type']) {
304                case 'CheckPHPConfig':
305                    $service = getService(json_encode($input), $input['type']);
306                    break;
307
308                default:
309                    // Unknown service.
310                    throw new tao_install_services_UnknownServiceException($input['type']);
311                    break;
312            }
313        } else {
314            switch ($input['type']) {
315                case 'Install':
316                    if (tao_install_utils_System::isTAOInstalled() && !tao_install_utils_System::isTAOInDebugMode()) {
317                        throw new NotAllowedAPICallException('The requested service is forbidden.');
318                    }
319
320                    $service = getService($rawInput, $input['type']);
321                    break;
322
323                case 'CheckPHPConfig':
324                case 'CheckPHPRuntime':
325                case 'CheckPHPINIValue':
326                case 'CheckPHPExtension':
327                case 'CheckPHPDatabaseDriver':
328                case 'CheckFileSystemComponent':
329                case 'CheckDatabaseConnection':
330                case 'CheckTAOForgeConnection':
331                case 'CheckCustom':
332                    $service = getService($rawInput, $input['type']);
333                    break;
334
335                default:
336                    // Unknown service.
337                    throw new tao_install_services_UnknownServiceException($input['type']);
338                    break;
339            }
340        }
341
342        // Execute service.
343        $service->execute();
344        $result = $service->getResult();
345        $contentType = $result->getMimeType();
346        $charset = $result->getEncoding();
347        header("Content-Type:${contentType}; charset=${charset}", 200);
348        echo $result->getContent();
349    }
350} catch (tao_install_services_UnknownServiceException $e) {
351    $serviceName = $e->getServiceName();
352    header('HTTP/1.0 404 Not Found');
353    header('Content-Type:text; charset=UTF-8');
354    echo "The requested service '${serviceName}' does not exist.";
355} catch (tao_install_api_MalformedRequestBodyException $e) {
356    header("HTTP/1.0 400 Bad Request");
357    header("Content-Type:text; charset=UTF-8");
358    echo "Request body could not be parsed as valid JSON.\n";
359    echo "Is your JSON data correctly formatted? You can check it on http://www.jslint.com, the JavaScript"
360        . " Quality Tool.\n";
361    echo "Make also sure your request body is UTF-8 encoded.";
362} catch (tao_install_api_InvalidAPICallException $e) {
363    header("HTTP/1.0 400 Bad Request");
364    header("Content-Type:text; charset=UTF-8");
365    echo $e->getMessage();
366} catch (NotAllowedAPICallException $e) {
367    header('HTTP/1.0 403 Forbidden');
368    header('Content-Type:text; charset=UTF-8');
369    echo "Error: " . $e->getMessage();
370} catch (Exception $e) {
371    header('HTTP/1.0 500 Internal Server Error');
372    header('Content-Type:text; charset=UTF-8');
373    echo "Fatal error: " . $e->getMessage();
374}
375$_SESSION = [];
376@session_destroy();