]> git.mxchange.org Git - friendica.git/blob - src/Core/System.php
Merge pull request #8227 from annando/daemon-checks
[friendica.git] / src / Core / System.php
1 <?php
2 /**
3  * @file src/Core/System.php
4  */
5 namespace Friendica\Core;
6
7 use Friendica\DI;
8 use Friendica\Network\HTTPException\InternalServerErrorException;
9 use Friendica\Util\XML;
10
11 /**
12  * @file include/Core/System.php
13  *
14  * Contains the class with system relevant stuff
15  */
16
17
18 /**
19  * System methods
20  */
21 class System
22 {
23         /**
24          * Returns a string with a callstack. Can be used for logging.
25          *
26          * @param integer $depth optional, default 4
27          * @return string
28          */
29         public static function callstack($depth = 4)
30         {
31                 $trace = debug_backtrace(DEBUG_BACKTRACE_IGNORE_ARGS);
32
33                 // We remove the first two items from the list since they contain data that we don't need.
34                 array_shift($trace);
35                 array_shift($trace);
36
37                 $callstack = [];
38                 $previous = ['class' => '', 'function' => ''];
39
40                 // The ignore list contains all functions that are only wrapper functions
41                 $ignore = ['fetchUrl', 'call_user_func_array'];
42
43                 while ($func = array_pop($trace)) {
44                         if (!empty($func['class'])) {
45                                 // Don't show multiple calls from the "dba" class to show the essential parts of the callstack
46                                 if ((($previous['class'] != $func['class']) || ($func['class'] != 'Friendica\Database\DBA')) && ($previous['function'] != 'q')) {
47                                         $classparts = explode("\\", $func['class']);
48                                         $callstack[] = array_pop($classparts).'::'.$func['function'];
49                                         $previous = $func;
50                                 }
51                         } elseif (!in_array($func['function'], $ignore)) {
52                                 $callstack[] = $func['function'];
53                                 $func['class'] = '';
54                                 $previous = $func;
55                         }
56                 }
57
58                 $callstack2 = [];
59                 while ((count($callstack2) < $depth) && (count($callstack) > 0)) {
60                         $callstack2[] = array_pop($callstack);
61                 }
62
63                 return implode(', ', $callstack2);
64         }
65
66         /**
67          * Generic XML return
68          * Outputs a basic dfrn XML status structure to STDOUT, with a <status> variable
69          * of $st and an optional text <message> of $message and terminates the current process.
70          *
71          * @param        $st
72          * @param string $message
73          * @throws \Exception
74          */
75         public static function xmlExit($st, $message = '')
76         {
77                 $result = ['status' => $st];
78
79                 if ($message != '') {
80                         $result['message'] = $message;
81                 }
82
83                 if ($st) {
84                         Logger::log('xml_status returning non_zero: ' . $st . " message=" . $message);
85                 }
86
87                 header("Content-type: text/xml");
88
89                 $xmldata = ["result" => $result];
90
91                 echo XML::fromArray($xmldata, $xml);
92
93                 exit();
94         }
95
96         /**
97          * Send HTTP status header and exit.
98          *
99          * @param integer $val     HTTP status result value
100          * @param string  $message Error message. Optional.
101          * @param string  $content Response body. Optional.
102          * @throws \Exception
103          */
104         public static function httpExit($val, $message = '', $content = '')
105         {
106                 Logger::log('http_status_exit ' . $val);
107                 header($_SERVER["SERVER_PROTOCOL"] . ' ' . $val . ' ' . $message);
108
109                 echo $content;
110
111                 exit();
112         }
113
114         public static function jsonError($httpCode, $data, $content_type = 'application/json')
115         {
116                 header($_SERVER["SERVER_PROTOCOL"] . ' ' . $httpCode);
117                 self::jsonExit($data, $content_type);
118         }
119
120         /**
121          * Encodes content to json.
122          *
123          * This function encodes an array to json format
124          * and adds an application/json HTTP header to the output.
125          * After finishing the process is getting killed.
126          *
127          * @param mixed  $x The input content.
128          * @param string $content_type Type of the input (Default: 'application/json').
129          */
130         public static function jsonExit($x, $content_type = 'application/json') {
131                 header("Content-type: $content_type");
132                 echo json_encode($x);
133                 exit();
134         }
135
136         /**
137          * Generates a random string in the UUID format
138          *
139          * @param bool|string $prefix A given prefix (default is empty)
140          * @return string a generated UUID
141          * @throws \Exception
142          */
143         public static function createUUID($prefix = '')
144         {
145                 $guid = System::createGUID(32, $prefix);
146                 return substr($guid, 0, 8) . '-' . substr($guid, 8, 4) . '-' . substr($guid, 12, 4) . '-' . substr($guid, 16, 4) . '-' . substr($guid, 20, 12);
147         }
148
149         /**
150          * Generates a GUID with the given parameters
151          *
152          * @param int         $size   The size of the GUID (default is 16)
153          * @param bool|string $prefix A given prefix (default is empty)
154          * @return string a generated GUID
155          * @throws \Exception
156          */
157         public static function createGUID($size = 16, $prefix = '')
158         {
159                 if (is_bool($prefix) && !$prefix) {
160                         $prefix = '';
161                 } elseif (empty($prefix)) {
162                         $prefix = hash('crc32', DI::baseUrl()->getHostname());
163                 }
164
165                 while (strlen($prefix) < ($size - 13)) {
166                         $prefix .= mt_rand();
167                 }
168
169                 if ($size >= 24) {
170                         $prefix = substr($prefix, 0, $size - 22);
171                         return str_replace('.', '', uniqid($prefix, true));
172                 } else {
173                         $prefix = substr($prefix, 0, max($size - 13, 0));
174                         return uniqid($prefix);
175                 }
176         }
177
178         /**
179          * Returns the current Load of the System
180          *
181          * @return integer
182          */
183         public static function currentLoad()
184         {
185                 if (!function_exists('sys_getloadavg')) {
186                         return false;
187                 }
188
189                 $load_arr = sys_getloadavg();
190
191                 if (!is_array($load_arr)) {
192                         return false;
193                 }
194
195                 return max($load_arr[0], $load_arr[1]);
196         }
197
198         /**
199          * Redirects to an external URL (fully qualified URL)
200          * If you want to route relative to the current Friendica base, use App->internalRedirect()
201          *
202          * @param string $url  The new Location to redirect
203          * @param int    $code The redirection code, which is used (Default is 302)
204          *
205          * @throws InternalServerErrorException If the URL is not fully qualified
206          */
207         public static function externalRedirect($url, $code = 302)
208         {
209                 if (empty(parse_url($url, PHP_URL_SCHEME))) {
210                         throw new InternalServerErrorException("'$url' is not a fully qualified URL, please use App->internalRedirect() instead");
211                 }
212
213                 switch ($code) {
214                         case 302:
215                                 // this is the default code for a REDIRECT
216                                 // We don't need a extra header here
217                                 break;
218                         case 301:
219                                 header('HTTP/1.1 301 Moved Permanently');
220                                 break;
221                         case 307:
222                                 header('HTTP/1.1 307 Temporary Redirect');
223                                 break;
224                 }
225
226                 header("Location: $url");
227                 exit();
228         }
229
230         /**
231          * Returns the system user that is executing the script
232          *
233          * This mostly returns something like "www-data".
234          *
235          * @return string system username
236          */
237         public static function getUser()
238         {
239                 if (!function_exists('posix_getpwuid') || !function_exists('posix_geteuid')) {
240                         return '';
241                 }
242
243                 $processUser = posix_getpwuid(posix_geteuid());
244                 return $processUser['name'];
245         }
246
247         /**
248          * Checks if a given directory is usable for the system
249          *
250          * @param      $directory
251          * @param bool $check_writable
252          *
253          * @return boolean the directory is usable
254          */
255         public static function isDirectoryUsable($directory, $check_writable = true)
256         {
257                 if ($directory == '') {
258                         Logger::log('Directory is empty. This shouldn\'t happen.', Logger::DEBUG);
259                         return false;
260                 }
261
262                 if (!file_exists($directory)) {
263                         Logger::log('Path "' . $directory . '" does not exist for user ' . static::getUser(), Logger::DEBUG);
264                         return false;
265                 }
266
267                 if (is_file($directory)) {
268                         Logger::log('Path "' . $directory . '" is a file for user ' . static::getUser(), Logger::DEBUG);
269                         return false;
270                 }
271
272                 if (!is_dir($directory)) {
273                         Logger::log('Path "' . $directory . '" is not a directory for user ' . static::getUser(), Logger::DEBUG);
274                         return false;
275                 }
276
277                 if ($check_writable && !is_writable($directory)) {
278                         Logger::log('Path "' . $directory . '" is not writable for user ' . static::getUser(), Logger::DEBUG);
279                         return false;
280                 }
281
282                 return true;
283         }
284
285         /// @todo Move the following functions from boot.php
286         /*
287         function local_user()
288         function public_contact()
289         function remote_user()
290         function notice($s)
291         function info($s)
292         function is_site_admin()
293         function get_temppath()
294         function get_cachefile($file, $writemode = true)
295         function get_itemcachepath()
296         function get_spoolpath()
297         */
298 }