Subversion Repositories oidplus

Rev

Rev 1219 | Rev 1247 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 daniel-mar 1
<?php
2
 
3
/*
4
 * OIDplus 2.0
1103 daniel-mar 5
 * Copyright 2019 - 2023 Daniel Marschall, ViaThinkSoft
2 daniel-mar 6
 *
7
 * Licensed under the Apache License, Version 2.0 (the "License");
8
 * you may not use this file except in compliance with the License.
9
 * You may obtain a copy of the License at
10
 *
11
 *     http://www.apache.org/licenses/LICENSE-2.0
12
 *
13
 * Unless required by applicable law or agreed to in writing, software
14
 * distributed under the License is distributed on an "AS IS" BASIS,
15
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16
 * See the License for the specific language governing permissions and
17
 * limitations under the License.
18
 */
19
 
1050 daniel-mar 20
use ViaThinkSoft\OIDplus\OIDplus;
1149 daniel-mar 21
use ViaThinkSoft\OIDplus\OIDplusException;
1050 daniel-mar 22
 
1130 daniel-mar 23
/**
24
 * @param string $privKey
25
 * @return bool
26
 */
27
function is_privatekey_encrypted(string $privKey): bool {
830 daniel-mar 28
        return strpos($privKey,'BEGIN ENCRYPTED PRIVATE KEY') !== false;
29
}
30
 
1130 daniel-mar 31
/**
32
 * @param string $privKey
33
 * @param string $pubKey
34
 * @return bool
35
 */
36
function verify_private_public_key(string $privKey, string $pubKey): bool {
721 daniel-mar 37
        if (!function_exists('openssl_public_encrypt')) return false;
74 daniel-mar 38
        try {
39
                if (empty($privKey)) return false;
40
                if (empty($pubKey)) return false;
453 daniel-mar 41
                $data = generateRandomString(25);
386 daniel-mar 42
                $encrypted = '';
43
                $decrypted = '';
74 daniel-mar 44
                if (!@openssl_public_encrypt($data, $encrypted, $pubKey)) return false;
45
                if (!@openssl_private_decrypt($encrypted, $decrypted, $privKey)) return false;
46
                return $decrypted == $data;
1050 daniel-mar 47
        } catch (\Exception $e) {
74 daniel-mar 48
                return false;
49
        }
50
}
51
 
1130 daniel-mar 52
/**
53
 * @param string $privKeyOld
54
 * @param string|null $passphrase_old
55
 * @param string|null $passphrase_new
56
 * @return false|string
57
 */
58
function change_private_key_passphrase(string $privKeyOld, string $passphrase_old=null, string $passphrase_new=null) {
830 daniel-mar 59
        $pkey_config = array(
60
            //"digest_alg" => "sha512",
61
            //"private_key_bits" => 2048,
62
            //"private_key_type" => OPENSSL_KEYTYPE_RSA,
1158 daniel-mar 63
            "config" => class_exists(OIDplus::class) ? OIDplus::getOpenSslCnf() : @getenv('OPENSSL_CONF')
830 daniel-mar 64
        );
65
        $privKeyNew = @openssl_pkey_get_private($privKeyOld, $passphrase_old);
66
        if ($privKeyNew === false) return false;
1116 daniel-mar 67
        if (!@openssl_pkey_export($privKeyNew, $privKeyNewExport, $passphrase_new, $pkey_config)) return false;
68
        if ($privKeyNewExport === "") return false;
69
        return "$privKeyNewExport";
830 daniel-mar 70
}
71
 
1130 daniel-mar 72
/**
73
 * @param string $privKey
74
 * @param string $passphrase
75
 * @return false|string
76
 */
77
function decrypt_private_key(string $privKey, string $passphrase) {
830 daniel-mar 78
        return change_private_key_passphrase($privKey, $passphrase, null);
79
}
80
 
1130 daniel-mar 81
/**
82
 * @param string $privKey
83
 * @param string $passphrase
84
 * @return false|string
85
 */
86
function encrypt_private_key(string $privKey, string $passphrase) {
830 daniel-mar 87
        return change_private_key_passphrase($privKey, null, $passphrase);
88
}
89
 
1130 daniel-mar 90
/**
91
 * @param string $data
92
 * @return int
93
 */
94
function smallhash(string $data): int { // get 31 bits from SHA1. Values 0..2147483647
250 daniel-mar 95
        return (hexdec(substr(sha1($data),-4*2)) & 0x7FFFFFFF);
74 daniel-mar 96
}
180 daniel-mar 97
 
1130 daniel-mar 98
/**
99
 * @param string $name
100
 * @return array
101
 */
102
function split_firstname_lastname(string $name): array {
182 daniel-mar 103
        $ary = explode(' ', $name);
104
        $last_name = array_pop($ary);
105
        $first_name = implode(' ', $ary);
106
        return array($first_name, $last_name);
107
}
108
 
1130 daniel-mar 109
/**
110
 * @return void
111
 */
180 daniel-mar 112
function originHeaders() {
113
        // CORS
114
        // Author: Till Wehowski
426 daniel-mar 115
        // TODO: add to class OIDplus
182 daniel-mar 116
 
180 daniel-mar 117
        header("Access-Control-Allow-Credentials: true");
118
        header("Access-Control-Allow-Origin: ".strip_tags(((isset($_SERVER['HTTP_ORIGIN'])) ? $_SERVER['HTTP_ORIGIN'] : "*")));
119
 
120
        header("Access-Control-Allow-Headers: If-None-Match, X-Requested-With, Origin, X-Frdlweb-Bugs, Etag, X-Forgery-Protection-Token, X-CSRF-Token");
121
 
122
        if (isset($_SERVER['HTTP_ORIGIN'])) {
123
                header('X-Frame-Options: ALLOW-FROM '.$_SERVER['HTTP_ORIGIN']);
124
        } else {
125
                header_remove("X-Frame-Options");
126
        }
127
 
128
        $expose = array('Etag', 'X-CSRF-Token');
129
        foreach (headers_list() as $num => $header) {
130
                $h = explode(':', $header);
131
                $expose[] = trim($h[0]);
132
        }
133
        header("Access-Control-Expose-Headers: ".implode(',',$expose));
134
 
135
        header("Vary: Origin");
136
}
236 daniel-mar 137
 
346 daniel-mar 138
if (!function_exists('mb_wordwrap')) {
1130 daniel-mar 139
        /**
140
         * @param string $str
141
         * @param int $width
142
         * @param string $break
143
         * @param bool $cut
144
         * @return string
145
         */
146
        function mb_wordwrap(string $str, int $width = 75, string $break = "\n", bool $cut = false): string {
346 daniel-mar 147
                // https://stackoverflow.com/a/4988494/488539
1231 daniel-mar 148
                assert(strlen($break) > 0);
149
                $lines = explode("$break", $str);
346 daniel-mar 150
                foreach ($lines as &$line) {
151
                        $line = rtrim($line);
152
                        if (mb_strlen($line) <= $width) {
153
                                continue;
154
                        }
155
                        $words = explode(' ', $line);
156
                        $line = '';
157
                        $actual = '';
158
                        foreach ($words as $word) {
159
                                if (mb_strlen($actual.$word) <= $width) {
160
                                        $actual .= $word.' ';
161
                                } else {
162
                                        if ($actual != '') {
163
                                                $line .= rtrim($actual).$break;
164
                                        }
165
                                        $actual = $word;
166
                                        if ($cut) {
167
                                                while (mb_strlen($actual) > $width) {
168
                                                        $line .= mb_substr($actual, 0, $width).$break;
169
                                                        $actual = mb_substr($actual, $width);
170
                                                }
171
                                        }
172
                                        $actual .= ' ';
173
                                }
174
                        }
175
                        $line .= trim($actual);
176
                }
177
                return implode($break, $lines);
178
        }
179
}
355 daniel-mar 180
 
1130 daniel-mar 181
/**
182
 * @param string $out
183
 * @param string $contentType
184
 * @param string $filename
185
 * @return void
186
 */
187
function httpOutWithETag(string $out, string $contentType, string $filename='') {
379 daniel-mar 188
        $etag = md5($out);
189
        header("Etag: $etag");
190
        header("Content-MD5: $etag"); // RFC 2616 clause 14.15
191
        if (isset($_SERVER['HTTP_IF_NONE_MATCH']) && (trim($_SERVER['HTTP_IF_NONE_MATCH']) == $etag)) {
1068 daniel-mar 192
                if (PHP_SAPI != 'cli') @http_response_code(304); // 304 Not Modified
379 daniel-mar 193
        } else {
194
                header("Content-Type: $contentType");
195
                if (!empty($filename)) {
196
                        header('Content-Disposition:inline; filename="'.$filename.'"');
197
                }
198
                echo $out;
199
        }
200
        die();
201
}
202
 
1130 daniel-mar 203
/**
204
 * @param string $str
205
 * @param array $args
206
 * @return string
207
 */
208
function my_vsprintf(string $str, array $args): string {
209
        $n = 1;
210
        foreach ($args as $val) {
211
                $str = str_replace("%$n", $val, $str);
212
                $n++;
213
        }
214
        return str_replace("%%", "%", $str);
360 daniel-mar 215
}
216
 
1130 daniel-mar 217
/**
218
 * @param string $str
219
 * @param mixed ...$sprintfArgs
220
 * @return string
221
 * @throws \ViaThinkSoft\OIDplus\OIDplusConfigInitializationException
222
 * @throws \ViaThinkSoft\OIDplus\OIDplusException
223
 */
224
function _L(string $str, ...$sprintfArgs): string {
401 daniel-mar 225
        static $translation_array = array();
226
        static $translation_loaded = null;
227
 
506 daniel-mar 228
        $str = trim($str);
229
 
1050 daniel-mar 230
        if (!class_exists(OIDplus::class)) {
438 daniel-mar 231
                return my_vsprintf($str, $sprintfArgs);
232
        }
233
 
360 daniel-mar 234
        $lang = OIDplus::getCurrentLang();
468 daniel-mar 235
        $ta = OIDplus::getTranslationArray($lang);
1162 daniel-mar 236
        $res = $ta[$lang][$str] ?? $str;
360 daniel-mar 237
 
238
        $res = str_replace('###', OIDplus::baseConfig()->getValue('TABLENAME_PREFIX', ''), $res);
239
 
1130 daniel-mar 240
        return my_vsprintf($res, $sprintfArgs);
370 daniel-mar 241
}
386 daniel-mar 242
 
1130 daniel-mar 243
/**
244
 * @param array $params
245
 * @param string $key
246
 * @return void
247
 * @throws \ViaThinkSoft\OIDplus\OIDplusConfigInitializationException
248
 * @throws \ViaThinkSoft\OIDplus\OIDplusException
249
 */
250
function _CheckParamExists(array $params, string $key) {
1050 daniel-mar 251
        if (class_exists(OIDplusException::class)) {
698 daniel-mar 252
                if (!isset($params[$key])) throw new OIDplusException(_L('Parameter %1 is missing', $key));
253
        } else {
254
                if (!isset($params[$key])) throw new Exception(_L('Parameter %1 is missing', $key));
255
        }
552 daniel-mar 256
}
257
 
1130 daniel-mar 258
/**
259
 * @param string $cont
260
 * @return array
261
 */
262
function extractHtmlContents(string $cont): array {
721 daniel-mar 263
        // make sure the program works even if the user provided HTML is not UTF-8
264
        $cont = convert_to_utf8_no_bom($cont);
265
 
386 daniel-mar 266
        $out_js = '';
267
        $m = array();
268
        preg_match_all('@<script[^>]*>(.+)</script>@ismU', $cont, $m);
269
        foreach ($m[1] as $x) {
270
                $out_js = $x . "\n\n";
271
        }
272
 
273
        $out_css = '';
274
        $m = array();
275
        preg_match_all('@<style[^>]*>(.+)</style>@ismU', $cont, $m);
276
        foreach ($m[1] as $x) {
277
                $out_css = $x . "\n\n";
278
        }
279
 
280
        $out_html = $cont;
281
        $out_html = preg_replace('@^(.+)<body[^>]*>@isU', '', $out_html);
282
        $out_html = preg_replace('@</body>.+$@isU', '', $out_html);
283
        $out_html = preg_replace('@<title>.+</title>@isU', '', $out_html);
284
        $out_html = preg_replace('@<h1>.+</h1>@isU', '', $out_html, 1);
285
        $out_html = preg_replace('@<script[^>]*>(.+)</script>@ismU', '', $out_html);
286
        $out_html = preg_replace('@<style[^>]*>(.+)</style>@ismU', '', $out_html);
287
 
288
        return array($out_html, $out_js, $out_css);
392 daniel-mar 289
}
290
 
1130 daniel-mar 291
/**
292
 * @param string $password
293
 * @param bool $raw_output
294
 * @return string
295
 * @throws Exception
296
 */
297
function sha3_512(string $password, bool $raw_output=false): string {
1103 daniel-mar 298
        if (hash_supported_natively('sha3-512')) {
400 daniel-mar 299
                return hash('sha3-512', $password, $raw_output);
392 daniel-mar 300
        } else {
1021 daniel-mar 301
                return \bb\Sha3\Sha3::hash($password, 512, $raw_output);
392 daniel-mar 302
        }
303
}
486 daniel-mar 304
 
1130 daniel-mar 305
/**
306
 * @param string $message
307
 * @param string $key
308
 * @param bool $raw_output
309
 * @return string
310
 */
311
function sha3_512_hmac(string $message, string $key, bool $raw_output=false): string {
710 daniel-mar 312
        // RFC 2104 HMAC
1103 daniel-mar 313
        if (hash_hmac_supported_natively('sha3-512')) {
847 daniel-mar 314
                return hash_hmac('sha3-512', $message, $key, $raw_output);
315
        } else {
1021 daniel-mar 316
                return \bb\Sha3\Sha3::hash_hmac($message, $key, 512, $raw_output);
847 daniel-mar 317
        }
710 daniel-mar 318
}
319
 
1130 daniel-mar 320
/**
321
 * @param string $password
322
 * @param string $salt
323
 * @param int $iterations
324
 * @param int $length
325
 * @param bool $binary
326
 * @return string
327
 */
328
function sha3_512_pbkdf2(string $password, string $salt, int $iterations, int $length=0, bool $binary=false): string {
1103 daniel-mar 329
        if (hash_pbkdf2_supported_natively('sha3-512')) {
330
                return hash_pbkdf2('sha3-512', $password, $salt, $iterations, $length, $binary);
331
        } else {
332
                return \bb\Sha3\Sha3::hash_pbkdf2($password, $salt, $iterations, 512, $length, $binary);
333
        }
334
}
335
 
1130 daniel-mar 336
/**
1181 daniel-mar 337
 * @param bool $require_ssl
338
 * @param string|null $reason
1149 daniel-mar 339
 * @return bool
1181 daniel-mar 340
 * @throws OIDplusException
341
 * @throws \ViaThinkSoft\OIDplus\OIDplusConfigInitializationException
1149 daniel-mar 342
 */
1181 daniel-mar 343
function url_post_contents_available(bool $require_ssl=true, string &$reason=null): bool {
1182 daniel-mar 344
        if (class_exists(OIDplus::class)) {
345
                if (OIDplus::baseConfig()->getValue('OFFLINE_MODE', false)) {
346
                        $reason = _L('OIDplus is running in offline mode due to the base configuration setting %1.', 'OFFLINE_MODE');
347
                        return false;
348
                }
349
        }
350
 
1181 daniel-mar 351
        if (function_exists('curl_init')) {
352
                return true;
353
        } else {
354
                $reason = _L('Please install the PHP extension %1, so that OIDplus can connect to the Internet.', '<code>php_curl</code>');
355
                return false;
356
        }
1149 daniel-mar 357
}
358
 
359
/**
1130 daniel-mar 360
 * @param string $url
1149 daniel-mar 361
 * @param array $params
362
 * @param array $extraHeaders
1130 daniel-mar 363
 * @param string $userAgent
364
 * @return string|false
1149 daniel-mar 365
 * @throws \ViaThinkSoft\OIDplus\OIDplusException
1130 daniel-mar 366
 */
1149 daniel-mar 367
function url_post_contents(string $url, array $params=array(), array $extraHeaders=array(), string $userAgent='ViaThinkSoft-OIDplus/2.0') {
1182 daniel-mar 368
        $require_ssl = str_starts_with(strtolower($url),'https:');
369
        if (!url_post_contents_available($require_ssl, $reason)) {
370
                throw new OIDplusException(_L('This feature is not available, because OIDplus cannot connect to the Internet.').' '.$reason);
371
        }
372
 
1149 daniel-mar 373
        $postFields = http_build_query($params);
374
 
375
        $headers = array(
376
                "User-Agent: $userAgent",
377
                "Content-Length: ".strlen($postFields)
378
        );
379
 
380
        foreach ($extraHeaders as $name => $val) {
381
                $headers[] = "$name: $val";
382
        }
383
 
653 daniel-mar 384
        if (function_exists('curl_init')) {
385
                $ch = curl_init();
1050 daniel-mar 386
                if (class_exists(OIDplus::class)) {
698 daniel-mar 387
                        if (ini_get('curl.cainfo') == '') curl_setopt($ch, CURLOPT_CAINFO, OIDplus::localpath() . 'vendor/cacert.pem');
388
                }
653 daniel-mar 389
                curl_setopt($ch, CURLOPT_URL, $url);
963 daniel-mar 390
                curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);
1149 daniel-mar 391
                curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
392
                curl_setopt($ch, CURLOPT_POST, true);
393
                curl_setopt($ch, CURLOPT_POSTFIELDS, $postFields);
653 daniel-mar 394
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
395
                curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
396
                curl_setopt($ch, CURLOPT_AUTOREFERER, true);
1006 daniel-mar 397
                $res = @curl_exec($ch);
963 daniel-mar 398
                $error_code = @curl_getinfo($ch, CURLINFO_HTTP_CODE);
1006 daniel-mar 399
                @curl_close($ch);
963 daniel-mar 400
                if ($error_code >= 400) return false;
1006 daniel-mar 401
                if ($res === false) return false;
653 daniel-mar 402
        } else {
1182 daniel-mar 403
                $res = false;
404
                assert(false);
1149 daniel-mar 405
        }
1182 daniel-mar 406
 
1149 daniel-mar 407
        return $res;
408
}
409
 
410
/**
1181 daniel-mar 411
 * @param bool $require_ssl
412
 * @param string|null $reason
413
 * @return bool
414
 * @throws OIDplusException
415
 * @throws \ViaThinkSoft\OIDplus\OIDplusConfigInitializationException
416
 */
417
function url_get_contents_available(bool $require_ssl=true, string &$reason=null): bool {
1182 daniel-mar 418
        if (class_exists(OIDplus::class)) {
419
                if (OIDplus::baseConfig()->getValue('OFFLINE_MODE', false)) {
420
                        $reason = _L('OIDplus is running in offline mode due to the base configuration setting %1.', 'OFFLINE_MODE');
421
                        return false;
422
                }
423
        }
424
 
1181 daniel-mar 425
        if (function_exists('curl_init')) {
426
                // Via cURL
427
                return true;
428
        } else {
429
                // Via file_get_contents()
430
                if (!ini_get('allow_url_fopen')) {
431
                        $reason = _L('Please install the PHP extension %1 and/or enable %2 in your PHP configuration, so that OIDplus can connect to the Internet.', '<code>php_curl</code>', '<code>allow_url_fopen</code>');
432
                        return false;
433
                }
434
                // Use extension_loaded() instead of function_exists(), because our supplement does not help...
435
                if ($require_ssl && !extension_loaded('openssl')) {
436
                        $reason = _L('Please install the PHP extension %1 and/or %2, so that OIDplus can connect to the Internet.', '<code>php_curl</code>', '<code>php_openssl</code>');
437
                        return false;
438
                }
439
                return true;
440
        }
441
}
442
 
443
/**
1149 daniel-mar 444
 * @param string $url
445
 * @param array $extraHeaders
446
 * @param string $userAgent
447
 * @return string|false
448
 */
449
function url_get_contents(string $url, array $extraHeaders=array(), string $userAgent='ViaThinkSoft-OIDplus/2.0') {
1182 daniel-mar 450
        $require_ssl = str_starts_with(strtolower($url),'https:');
451
        if (!url_get_contents_available($require_ssl, $reason)) {
452
                throw new OIDplusException(_L('This feature is not available, because OIDplus cannot connect to the Internet.').' '.$reason);
453
        }
454
 
1149 daniel-mar 455
        $headers = array("User-Agent: $userAgent");
456
        foreach ($extraHeaders as $name => $val) {
457
                $headers[] = "$name: $val";
458
        }
459
        if (function_exists('curl_init')) {
460
                $ch = curl_init();
461
                if (class_exists(OIDplus::class)) {
462
                        if (ini_get('curl.cainfo') == '') curl_setopt($ch, CURLOPT_CAINFO, OIDplus::localpath() . 'vendor/cacert.pem');
463
                }
464
                curl_setopt($ch, CURLOPT_URL, $url);
465
                curl_setopt($ch, CURLOPT_USERAGENT, $userAgent);
466
                curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
467
                curl_setopt($ch, CURLOPT_POST, false);
468
                curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
469
                curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);
470
                curl_setopt($ch, CURLOPT_AUTOREFERER, true);
471
                $res = @curl_exec($ch);
472
                $error_code = @curl_getinfo($ch, CURLINFO_HTTP_CODE);
473
                @curl_close($ch);
474
                if ($error_code >= 400) return false;
475
                if ($res === false) return false;
476
        } else {
963 daniel-mar 477
                // Attention: HTTPS only works if OpenSSL extension is enabled.
478
                // Our supplement does not help...
716 daniel-mar 479
                $opts = [
480
                        "http" => [
481
                                "method" => "GET",
1149 daniel-mar 482
                                "header" => implode("\r\n",$headers)."\r\n"
716 daniel-mar 483
                        ]
484
                ];
485
                $context = stream_context_create($opts);
486
                $res = @file_get_contents($url, false, $context);
653 daniel-mar 487
                if ($res === false) return false;
488
        }
489
        return $res;
660 daniel-mar 490
}
778 daniel-mar 491
 
1130 daniel-mar 492
/**
493
 * @return string
494
 */
495
function getSortedQuery(): string {
778 daniel-mar 496
        // https://stackoverflow.com/a/51777249/488539
497
        $url = [];
498
        parse_str($_SERVER['QUERY_STRING'], $url);
499
        ksort($url);
500
        return http_build_query($url);
501
}
1148 daniel-mar 502
 
503
/**
504
* @param array &$rows
505
* @param string $fieldName
506
* @return void
507
*/
1158 daniel-mar 508
function natsort_field(array &$rows, string $fieldName) {
1148 daniel-mar 509
        usort($rows, function($a,$b) use($fieldName) {
510
                if ($a[$fieldName] == $b[$fieldName]) return 0; // equal
511
                $ary = array(
512
                        -1 => $a[$fieldName],
513
                        1 => $b[$fieldName]
514
                );
1150 daniel-mar 515
                natsort($ary);
1148 daniel-mar 516
                $keys = array_keys($ary);
517
                return $keys[0];
518
        });
519
}
1156 daniel-mar 520
 
521
/**
522
 * @param array $ary
523
 * @return \stdClass
524
 */
525
function array_to_stdobj(array $ary): \stdClass {
526
        $obj = new \stdClass;
527
        foreach ($ary as $name => $val) {
528
                $obj->$name = $val;
529
        }
530
        return $obj;
531
}
532
 
533
/**
534
 * @param \stdClass $obj
535
 * @return array
536
 */
537
function stdobj_to_array(\stdClass $obj): array {
538
        $ary = array();
1190 daniel-mar 539
        foreach ($obj as $name => $val) { /* @phpstan-ignore-line */
1156 daniel-mar 540
                $ary[$name] = $val;
541
        }
542
        return $ary;
543
}
1180 daniel-mar 544
 
545
/**
546
 * @return string|false
547
 */
548
function get_own_username() {
549
        $current_user = exec('whoami');
550
        if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
551
                try {
552
                        if (function_exists('mb_convert_encoding')) {
553
                                $current_user = @mb_convert_encoding($current_user, "UTF-8", "cp850");
554
                        } else if (function_exists('iconv')) {
555
                                $current_user = @iconv("cp850", "UTF-8", $current_user);
556
                        }
557
                } catch (\Exception $e) {}
558
                if (function_exists('mb_strtoupper')) {
559
                        $current_user = mb_strtoupper($current_user); // just cosmetics
560
                }
561
        }
562
        if (!$current_user) {
563
                if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') {
564
                        // Windows on an IIS server:
565
                        //     getenv('USERNAME')     MARSCHALL$                (That is the "machine account", see https://docs.microsoft.com/en-us/iis/manage/configuring-security/application-pool-identities#accessing-the-network )
566
                        //     get_current_user()     DefaultAppPool
567
                        //     exec('whoami')         iis apppool\defaultapppool
568
                        // Windows with XAMPP:
569
                        //     getenv('USERNAME')     dmarschall
570
                        //     get_current_user()     dmarschall               (even if script has a different NTFS owner!)
571
                        //     exec('whoami')         hickelsoft\dmarschall
572
                        $current_user = get_current_user();
573
                        if (!$current_user) {
574
                                $current_user = getenv('USERNAME');
575
                                $current_user = mb_strtoupper($current_user); // just cosmetics
576
                        }
577
                } else {
578
                        // On Linux:
579
                        $current_user = exec('id -un');
580
                        if (!$current_user) {
581
                                // PHP'S get_current_user() will get the owner of the PHP script, not the process owner!
582
                                // We want the process owner, so we use posix_geteuid() preferably.
583
                                if (function_exists('posix_geteuid')) {
584
                                        $uid = posix_geteuid();
585
                                } else {
586
                                        $temp_file = tempnam(sys_get_temp_dir(), 'TMP');
587
                                        if ($temp_file !== false) {
588
                                                $uid = fileowner($temp_file);
589
                                                if ($uid === false) $uid = -1;
590
                                                @unlink($temp_file);
591
                                        } else {
592
                                                $uid = -1;
593
                                        }
594
                                }
595
                                if ($uid >= 0) {
596
                                        $current_user = '#' . $uid;
597
                                        if (function_exists('posix_getpwuid')) {
598
                                                $userinfo = posix_getpwuid($uid); // receive username from the UID (requires read access to /etc/passwd)
599
                                                if ($userinfo !== false) $current_user = $userinfo['name'];
600
                                        }
601
                                } else {
602
                                        $current_user = get_current_user();
603
                                }
604
                        }
605
                }
606
        }
607
        return $current_user ?: false;
608
}
609
 
610
/**
611
 * @param string $path
612
 * @return bool
613
 */
614
function isFileOrPathWritable(string $path): bool {
615
        if ($writable_file = (file_exists($path) && is_writable($path))) return true;
616
        if ($writable_directory = (!file_exists($path) && is_writable(dirname($path)))) return true;
617
        return false;
1190 daniel-mar 618
}
1219 daniel-mar 619
 
620
/**
621
 * @param string $html
622
 * @return string
623
 */
624
function html_to_text(string $html): string {
625
        $html = str_replace("\n", "", $html);
626
        $html = str_ireplace('<br', "\n<br", $html);
627
        $html = str_ireplace('<p', "\n\n<p", $html);
628
        $html = strip_tags($html);
629
        $html = html_entity_decode($html, ENT_QUOTES, 'UTF-8');
630
        return $html;
631
}