2
0

CheckIosAppStore.php 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. <?php
  2. namespace App\Console\Commands;
  3. use App\Notification\TelegramBot;
  4. use App\Util;
  5. use Illuminate\Console\Command;
  6. /**
  7. * 检测配置的 iOS App Store 包是否被下架,若下架则通过 Telegram 通知。
  8. */
  9. class CheckIosAppStore extends Command
  10. {
  11. protected $signature = 'ios:check-app-store';
  12. protected $description = '检测 iOS App Store 包是否被下架,下架时 Telegram 通知';
  13. /** 要检测的 iOS 包列表:name => url */
  14. protected $apps = [
  15. ];
  16. /** 页面内容中表示“已下架”的关键词(不区分大小写) */
  17. protected $delistedKeywords = [
  18. 'no longer available',
  19. 'removed this app from the app store',
  20. 'not available',
  21. 'this app is no longer',
  22. 'has been removed',
  23. ];
  24. public function handle()
  25. {
  26. $env = env('APP_ENV', 'local');
  27. $delisted = [];
  28. foreach ($this->apps as $name => $url) {
  29. $result = $this->checkApp($url);
  30. if ($result['delisted']) {
  31. $delisted[] = [
  32. 'name' => $name,
  33. 'url' => $url,
  34. 'reason' => $result['reason'],
  35. ];
  36. Util::WriteLog('ios_app_store_check', "Delisted: {$name} | {$url} | {$result['reason']}");
  37. }
  38. }
  39. if (count($delisted) > 0) {
  40. $this->notifyDelisted($env, $delisted);
  41. $this->warn('已检测到 ' . count($delisted) . ' 个包被下架,已发送 Telegram 通知。');
  42. return 1;
  43. }
  44. $this->info('所有 iOS 包状态正常。');
  45. return 0;
  46. }
  47. /**
  48. * 检测单个 App 是否可访问(未下架)
  49. * @return array ['delisted' => bool, 'reason' => string]
  50. */
  51. protected function checkApp($url)
  52. {
  53. $ch = curl_init($url);
  54. curl_setopt_array($ch, [
  55. CURLOPT_RETURNTRANSFER => true,
  56. CURLOPT_FOLLOWLOCATION => true,
  57. CURLOPT_TIMEOUT => 15,
  58. CURLOPT_USERAGENT => 'Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36',
  59. CURLOPT_SSL_VERIFYPEER => true,
  60. ]);
  61. $body = curl_exec($ch);
  62. $code = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE);
  63. $error = curl_error($ch);
  64. curl_close($ch);
  65. if ($error) {
  66. return ['delisted' => true, 'reason' => "请求失败: {$error}"];
  67. }
  68. if ($code === 404) {
  69. return ['delisted' => true, 'reason' => 'HTTP 404'];
  70. }
  71. if ($code !== 200) {
  72. return ['delisted' => true, 'reason' => "HTTP {$code}"];
  73. }
  74. $bodyLower = mb_strtolower($body);
  75. foreach ($this->delistedKeywords as $keyword) {
  76. if (strpos($bodyLower, $keyword) !== false) {
  77. return ['delisted' => true, 'reason' => "页面包含下架提示: {$keyword}"];
  78. }
  79. }
  80. return ['delisted' => false, 'reason' => ''];
  81. }
  82. protected function notifyDelisted($env, array $delisted)
  83. {
  84. $lines = ["[{$env}] iOS App Store 下架检测告警"];
  85. foreach ($delisted as $item) {
  86. $lines[] = "• {$item['name']}";
  87. $lines[] = " 原因: {$item['reason']}";
  88. $lines[] = " 链接: {$item['url']}";
  89. }
  90. $message = implode("\n", $lines);
  91. try {
  92. TelegramBot::getDefault()->sendMsg($message);
  93. } catch (\Exception $e) {
  94. Util::WriteLog('ios_app_store_check', 'Telegram send error: ' . $e->getMessage());
  95. $this->error('Telegram 发送失败: ' . $e->getMessage());
  96. }
  97. }
  98. }