Merge pull request 'PHP 8.5が必須になった' (#33) from php85 into master
Reviewed-on: http://192.168.10.104:3000/suwako/LittleBeast/pulls/33
suwako <suwako@076.moe>、2026-05-06 03:51
コミット 65fa46e5a92ba07732e70c0acaaab8a8e20b2be9
・親 0223951
・親 ca9e2f8
・ファイルを見る
9個のファイル、+33 -37
変更
CHANGELOG.md
| @@ -1,5 +1,6 @@ | ||
| 1 | 1 | # 0.5 (2026年??月??日) |
| 2 | 2 | * OpenProviderライブラリ |
| 3 | +* PHP 8.5以上が必須になった | |
| 3 | 4 | |
| 4 | 5 | # ローリング・リリース (2025年01月01日) |
| 5 | 6 | * 最初プライベートリリース |
変更
README-JP.md
| @@ -7,7 +7,7 @@ | ||
| 7 | 7 | サンプル:[https://lbdemo.technicalsuwako.moe/](https://lbdemo.technicalsuwako.moe/) |
| 8 | 8 | |
| 9 | 9 | ## Little Beast とは? |
| 10 | -Little Beast は PHP 8.3 以上向けのフレームワークで、076.moe(ゲーム開発会社)と technicalsuwako.moe(社長のブログ)向けに作られました。\ | |
| 10 | +Little Beast は PHP 8.5 以上向けのフレームワークで、076.moe(ゲーム開発会社)と technicalsuwako.moe(社長のブログ)向けに作られました。\ | |
| 11 | 11 | メイン考え方は「必要な物だけ拡張し、不要な物は削除する」です。\ |
| 12 | 12 | 各コア機能はライブラリに分割されている為、必要な物だけを選び易い設計になっています。\ |
| 13 | 13 | 全てのモジュールはゼロから書かれており、データベースは一切必要ありません。 |
| @@ -68,9 +68,9 @@ | ||
| 68 | 68 | |
| 69 | 69 | ### OpenBSD サーバー |
| 70 | 70 | ```sh |
| 71 | -pkg_add php-8.4.14 php-gmp-8.4.14 | |
| 72 | -rcctl enable php84_fpm httpd relayd | |
| 73 | -rcctl start php84_fpm httpd relayd | |
| 71 | +pkg_add php-8.5.5 php-gmp-8.5.5 | |
| 72 | +rcctl enable php85_fpm httpd relayd | |
| 73 | +rcctl start php85_fpm httpd relayd | |
| 74 | 74 | ``` |
| 75 | 75 | |
| 76 | 76 | #### httpd |
変更
README.md
| @@ -7,7 +7,7 @@ | ||
| 7 | 7 | Demo installation: [https://lbdemo.technicalsuwako.moe/](https://lbdemo.technicalsuwako.moe/) |
| 8 | 8 | |
| 9 | 9 | ## What is Little Beast? |
| 10 | -Little Beast is a PHP 8.3 or above framework made for 076.moe (game developer company) and technicalsuwako.moe (CEO's blog).\ | |
| 10 | +Little Beast is a PHP 8.5 or above framework made for 076.moe (game developer company) and technicalsuwako.moe (CEO's blog).\ | |
| 11 | 11 | The core mentality is to extend what you need, and remove what you don't need.\ |
| 12 | 12 | Each core feature is split into libraries, so it is easy to choose what you need.\ |
| 13 | 13 | All modules are written from scratch, nothing is to be require a database. |
| @@ -68,9 +68,9 @@ | ||
| 68 | 68 | |
| 69 | 69 | ### OpenBSD server |
| 70 | 70 | ```sh |
| 71 | -pkg_add php-8.4.14 php-gmp-8.4.14 | |
| 72 | -rcctl enable php84_fpm httpd relayd | |
| 73 | -rcctl start php84_fpm httpd relayd | |
| 71 | +pkg_add php-8.5.5 php-gmp-8.5.5 | |
| 72 | +rcctl enable php85_fpm httpd relayd | |
| 73 | +rcctl start php85_fpm httpd relayd | |
| 74 | 74 | ``` |
| 75 | 75 | |
| 76 | 76 | #### httpd |
変更
route.php
| @@ -66,7 +66,7 @@ | ||
| 66 | 66 | ]; |
| 67 | 67 | |
| 68 | 68 | if (ACTIVITYPUB_ENABLED) { |
| 69 | - $routes[] = Route::add('GET', '.well-known/webfinger', Home::class.'@apfinger'); | |
| 69 | + $routes[] = Route::add('GET', '.well-known/webfinger', Fediverse::class.'@apfinger'); | |
| 70 | 70 | $routes[] = Route::add('GET', 'ap/following', Fediverse::class.'@apfollowing'); |
| 71 | 71 | $routes[] = Route::add('GET', 'ap/followers', Fediverse::class.'@apfollowers'); |
| 72 | 72 | $routes[] = Route::add('GET', 'ap/outbox', Fediverse::class.'@apoutbox'); |
| @@ -39,6 +39,7 @@ | ||
| 39 | 39 | |
| 40 | 40 | use Std\Lib\Curl; |
| 41 | 41 | use LogType; |
| 42 | +use Uri\Rfc3986\Uri; | |
| 42 | 43 | |
| 43 | 44 | /** |
| 44 | 45 | * ActivityPubプロトコルの実装クラス |
| @@ -298,14 +299,14 @@ | ||
| 298 | 299 | */ |
| 299 | 300 | public function getWebfinger(): string { |
| 300 | 301 | if (!ACTIVITYPUB_ENABLED) return ''; |
| 301 | - $domain = str_replace(['http://', 'https://'], '', $this->domain); | |
| 302 | + $uri = new Uri($this->domain); | |
| 302 | 303 | $webfinger = [ |
| 303 | - 'subject' => "acct:{$this->actor}@{$domain}", | |
| 304 | + 'subject' => "acct:{$this->actor}@{$uri->getHost()}", | |
| 304 | 305 | 'links' => [ |
| 305 | 306 | [ |
| 306 | 307 | 'rel' => 'self', |
| 307 | 308 | 'type' => 'application/activity+json', |
| 308 | - 'href' => "{$domain}/ap/actor", | |
| 309 | + 'href' => "{$this->domain}/ap/actor", | |
| 309 | 310 | ], |
| 310 | 311 | ], |
| 311 | 312 | ]; |
| @@ -445,10 +446,10 @@ | ||
| 445 | 446 | $body = json_encode($activity, JSON_UNESCAPED_SLASHES); |
| 446 | 447 | $digest = base64_encode(hash('sha256', $body, true)); |
| 447 | 448 | $date = gmdate('D, d M Y H:i:s \G\M\T'); |
| 448 | - $host = parse_url($inboxUrl, PHP_URL_HOST); | |
| 449 | + $uri = new Uri($inboxUrl); | |
| 449 | 450 | |
| 450 | 451 | $headers = [ |
| 451 | - 'Host' => $host, | |
| 452 | + 'Host' => $uri->getHost().($uri->getPort() ? ':'.$uri->getPort() : ''), | |
| 452 | 453 | 'Date' => $date, |
| 453 | 454 | 'Content-Type' => 'application/activity+json', |
| 454 | 455 | 'Digest' => "SHA-256=$digest", |
| @@ -38,6 +38,7 @@ | ||
| 38 | 38 | namespace Std\Lib; |
| 39 | 39 | |
| 40 | 40 | use Result; |
| 41 | +use Uri\Rfc3986\Uri; | |
| 41 | 42 | |
| 42 | 43 | /** |
| 43 | 44 | * php_curlへの依存を排除するための独自のCURL実装 |
| @@ -354,19 +355,18 @@ | ||
| 354 | 355 | fwrite($this->stderr, "* 接続中: {$currentUrl}\n"); |
| 355 | 356 | } |
| 356 | 357 | |
| 357 | - $parsed = parse_url($currentUrl); | |
| 358 | - if (!$parsed) { | |
| 358 | + $uri = new Uri($currentUrl); | |
| 359 | + if (!$uri) { | |
| 359 | 360 | $this->responseError = "無効なURL: {$currentUrl}"; |
| 360 | 361 | return Result::Error($this->responseError); |
| 361 | 362 | } |
| 362 | 363 | |
| 363 | - $scheme = isset($parsed['scheme']) ? strtolower($parsed['scheme']) : 'http'; | |
| 364 | - $host = $parsed['host']; | |
| 365 | - $port = isset($parsed['port']) | |
| 366 | - ? $parsed['port'] : ($scheme === 'https' ? 443 : 80); | |
| 367 | - $path = isset($parsed['path']) ? $parsed['path'] : '/'; | |
| 368 | - if (isset($parsed['query'])) { | |
| 369 | - $path .= '?'.$parsed['query']; | |
| 364 | + $scheme = $uri->getScheme() ?? 'http'; | |
| 365 | + $port = $uri->getPort() ?? ($scheme === 'https' ? 443 : 80); | |
| 366 | + $path = $uri->getPath(); | |
| 367 | + if ($path === '') $path = '/'; | |
| 368 | + if (NULL !== $uri->getQuery()) { | |
| 369 | + $path .= '?'.$uri->getQuery(); | |
| 370 | 370 | } |
| 371 | 371 | |
| 372 | 372 | // 認証 |
| @@ -404,7 +404,7 @@ | ||
| 404 | 404 | } |
| 405 | 405 | |
| 406 | 406 | $request = "{$method} {$path} HTTP/1.1\r\n"; |
| 407 | - $request .= "Host: {$host}\r\n"; | |
| 407 | + $request .= "Host: {$uri->getHost()}\r\n"; | |
| 408 | 408 | $request .= "User-Agent: {$this->userAgent}\r\n"; |
| 409 | 409 | $request .= "{$accept}\r\n"; |
| 410 | 410 | $request .= "Connection: close\r\n"; |
| @@ -462,7 +462,7 @@ | ||
| 462 | 462 | $context = stream_context_create(['ssl' => $sslOptions]); |
| 463 | 463 | |
| 464 | 464 | $socket = @stream_socket_client( |
| 465 | - "tls://{$host}:{$port}", | |
| 465 | + "tls://{$uri->getHost()}:{$port}", | |
| 466 | 466 | $errno, |
| 467 | 467 | $errstr, |
| 468 | 468 | $this->timeout, |
| @@ -470,7 +470,7 @@ | ||
| 470 | 470 | $context |
| 471 | 471 | ); |
| 472 | 472 | } else { |
| 473 | - $socket = @fsockopen($host, $port, $errno, $errstr, $this->timeout); | |
| 473 | + $socket = @fsockopen($uri->getHost(), $port, $errno, $errstr, $this->timeout); | |
| 474 | 474 | } |
| 475 | 475 | |
| 476 | 476 | if (!$socket) { |
| @@ -637,9 +637,9 @@ | ||
| 637 | 637 | |
| 638 | 638 | if (strpos($redirectUrl, 'http') !== 0) { |
| 639 | 639 | if ($redirectUrl[0] === '/') { |
| 640 | - $parsed = parse_url($currentUrl); | |
| 641 | - $redirectUrl = $parsed['scheme'].'://'.$parsed['host'] | |
| 642 | - .(isset($parsed['port']) ? ':'.$parsed['port'] : '') | |
| 640 | + $uri = new Uri($currentUrl); | |
| 641 | + $redirectUrl = $uri->getScheme().'://'.$uri->getHost() | |
| 642 | + .(NULL !== $uri->getPort() ? ':'.$uri->getPort() : '') | |
| 643 | 643 | .$redirectUrl; |
| 644 | 644 | } else { |
| 645 | 645 | $redirectUrl = dirname($currentUrl).'/'.$redirectUrl; |
| @@ -407,6 +407,7 @@ | ||
| 407 | 407 | */ |
| 408 | 408 | public function assertArrayHasKey(mixed $key, array $array, |
| 409 | 409 | ?string $message = null): Tester { |
| 410 | + if (NULL === $key) throw new AssertionFailedException("配列鍵がありません"); | |
| 410 | 411 | if (!is_array($array) && !($array instanceof \ArrayAccess)) { |
| 411 | 412 | throw new AssertionFailedException( |
| 412 | 413 | '第2引数は配列又はArrayAccessを実装している必要があります'); |
変更
util.php
| @@ -471,10 +471,3 @@ | ||
| 471 | 471 | while ($lower * 2 <= $val) $lower *= 2; |
| 472 | 472 | return $lower; |
| 473 | 473 | } |
| 474 | - | |
| 475 | -// PHP 8.3と8.4の場合 | |
| 476 | -if (!function_exists('array_last')) { | |
| 477 | - function array_last(array $array): mixed { | |
| 478 | - return $array === [] ? null : $array[array_key_last($array)]; | |
| 479 | - } | |
| 480 | -} |
| @@ -20,7 +20,7 @@ | ||
| 20 | 20 | {@ endif @} |
| 21 | 21 | {@ endif @} |
| 22 | 22 | <meta name="description" content="{{ $description }}" /> |
| 23 | - <meta name="keywords" content="{{ SITEINFO['tags'].(isset($meta->category) ? ',' : '') }}{@ if (isset($meta) && isset($meta->category)) @}{@ foreach ($meta->category as $k => $cat) @}{{ $cat.($k === array_key_last($meta->category) ? '' : ',') }}{@ endforeach @}{@ endif @}" /> | |
| 23 | + <meta name="keywords" content="{{ SITEINFO['tags'].(isset($meta->category) ? ','.implode(',', $meta->category) : '') }}" /> | |
| 24 | 24 | |
| 25 | 25 | <meta property="og:title" content="{{ SITEINFO['title'] }}: {{ $pagetit }}" /> |
| 26 | 26 | <meta property="og:description" content="{{ $description }}" /> |