Status.class.php (5882B)
1 <?php 2 3 namespace cms\status; 4 5 use BadMethodCallException; 6 use cms\action\RequestParams; 7 use cms\base\Configuration; 8 use cms\base\DB; 9 use cms\base\DefaultConfig; 10 use cms\base\Startup; 11 use cms\Dispatcher; 12 use cms\update\Update; 13 use configuration\Config; 14 use configuration\ConfigurationLoader; 15 use database\Database; 16 use Exception; 17 use util\Http; 18 use logger\Logger; 19 use \util\exception\ObjectNotFoundException; 20 use util\exception\UIException; 21 use util\exception\SecurityException; 22 use util\json\JSON; 23 use util\Session; 24 use util\XML; 25 use util\YAML; 26 27 /** 28 * Actuator. 29 */ 30 class Status 31 { 32 /** 33 * Getting the state 34 */ 35 public static function execute() 36 { 37 $cmd = $_SERVER['QUERY_STRING']; 38 $data = []; 39 $success = false; 40 41 switch( $cmd ) { 42 case '': 43 case 'health': 44 case 'status': 45 case 'state': 46 47 $data['state'] = 'UP'; 48 $success = true; 49 break; 50 51 case 'db': 52 case 'database': 53 54 $config = new Config( self::getConfiguration() ); 55 $databases = []; 56 foreach( $config->subset('database')->subsets() as $dbName => $dbConfig ) { 57 58 if (!$dbConfig->is('enabled', true)) { 59 $dbState = [ 60 'state' => 'DISABLED', 61 ]; 62 63 } else { 64 65 try { 66 $db = new Database($dbConfig->subset('read')->getConfig() + $dbConfig->getConfig()); 67 68 $update = new Update(); 69 70 if ( $update->isUpdateRequired( $db ) ) 71 $dbState = [ 72 'state' => 'UP', 73 ]; 74 else 75 $dbState = [ 76 'state' => 'DOWN', 77 'message' => 'NEEDS UPGRADE', 78 ]; 79 80 $db->disconnect(); 81 82 } catch (\Exception $e) { 83 $dbState = [ 84 'state' => 'DOWN', 85 'message' => $e->getMessage(), 86 ]; 87 } 88 89 } 90 91 $databases[$dbName] = $dbState; 92 } 93 94 $data['databases'] = $databases; 95 $success = true; 96 break; 97 98 case 'upgrade': 99 case 'update': 100 case 'install': 101 102 $config = new Config( self::getConfiguration() ); 103 $databases = []; 104 foreach( $config->subset('database')->subsets() as $dbName => $dbConfig ) { 105 106 $dbState = []; 107 108 if (!$dbConfig->is('enabled', true)) { 109 $dbState = [ 110 'state' => 'DISABLED', 111 ]; 112 113 } else { 114 115 try { 116 $adminDb = new Database($dbConfig->subset('admin')->getConfig() + $dbConfig->getConfig()); 117 $adminDb->id = $dbName; 118 119 $updater = new Update(); 120 121 if ( ! $updater->isUpdateRequired( $adminDb ) ) { 122 $dbState = [ 123 'state' => 'UP', 124 ]; 125 } 126 else { 127 128 if (!$dbConfig->is('auto_update', true)) 129 $dbState = [ 130 'state' => 'DOWN', 131 'message' => 'DB Update required, but auto-update is disabled. ' . Startup::TITLE . " " . Startup::VERSION . " needs DB-version " . Update::SUPPORTED_VERSION 132 ]; 133 else { 134 $updater->update($adminDb); 135 136 // Try to close the PDO connection. PDO doc: 137 // To close the connection, you need to destroy the object by ensuring that all 138 // remaining references to it are deleted—you do this by assigning NULL to the variable that holds the object. 139 // If you don't do this explicitly, PHP will automatically close the connection when your script ends. 140 $adminDb = null; 141 unset($adminDb); 142 143 $dbState = [ 144 'state' => 'UP', 145 'message' => 'Updated', 146 ]; 147 } 148 } 149 150 151 } catch (\Exception $e) { 152 $dbState = [ 153 'state' => 'DOWN', 154 'message' => $e->getMessage(), 155 ]; 156 } 157 158 } 159 160 $databases[$dbName] = $dbState; 161 } 162 163 $data['databases'] = $databases; 164 $success = true; 165 break; 166 167 case 'info': 168 $data = [ 169 'version' => Startup::VERSION, 170 'date' => Startup::DATE, 171 'name' => Startup::TITLE, 172 'api' => Startup::API_LEVEL, 173 ]; 174 $success = true; 175 break; 176 177 case 'system': 178 $data = [ 179 'interpreter' => PHP_VERSION, 180 'os' => PHP_OS, 181 'usage' => getrusage(), 182 'memory' => [ 183 'allocated' => memory_get_usage(true), 184 'used' => memory_get_usage(), 185 'peak_allocated' => memory_get_peak_usage(true), 186 'peak_used' => memory_get_peak_usage(), 187 188 ], 189 ]; 190 $success = true; 191 break; 192 193 case 'env': 194 case 'environment': 195 if ( version_compare(PHP_VERSION,'7.1','>=') ) 196 $data['environment'] = getenv(); // since PHP 7.1 197 $success = true; 198 break; 199 200 case 'server': 201 $data['server'] = $_SERVER; 202 $success = true; 203 break; 204 205 case 'extensions': 206 $data['extensions'] = get_loaded_extensions(); 207 $success = true; 208 break; 209 210 case 'config': 211 case 'configuration': 212 213 $data['configuration'] = self::getConfiguration(); 214 $success = true; 215 216 break; 217 218 default: 219 } 220 221 // Be safe! We must clear secret values. 222 array_walk_recursive($data, function(&$value,$key) { 223 if ( stripos($key,'secret' ) !== FALSE || 224 stripos($key,'password') !== FALSE || 225 stripos($key,'pass' ) !== FALSE ) 226 $value = '**********'; 227 }); 228 229 230 header('Content-Type: application/json; charset=UTF-8'); 231 $output = JSON::encode($data); 232 233 if (!headers_sent()) { 234 // HTTP Spec: 235 // "Applications SHOULD use this field to indicate the transfer-length of the 236 // message-body, unless this is prohibited by the rules in section 4.4." 237 // 238 // And the overhead of 'Transfer-Encoding: chunked' is eliminated... 239 header('HTTP/1.0 ' . ($success ? '200 OK' : '503 Internal Server Error') ); 240 header('Content-Length: ' . strlen($output)); 241 242 } 243 244 echo $output; 245 } 246 247 248 private static function getConfiguration() { 249 $configFile = getenv( 'CMS_CONFIG_FILE' ); 250 if ( ! $configFile ) 251 $configFile = Startup::DEFAULT_CONFIG_FILE; 252 253 $configLoader = new ConfigurationLoader( $configFile ); 254 return $configLoader->load(); 255 } 256 }