Checker.php 9.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245
  1. <?php
  2. namespace WORKERMAN\Core\Lib;
  3. /**
  4. * 环境检查相关
  5. *
  6. * @author walkor <worker-man@qq.com>
  7. */
  8. class Checker
  9. {
  10. /**
  11. * 检查启动worker进程的的用户是否合法
  12. * @return void
  13. */
  14. public static function checkWorkerUserName($worker_user)
  15. {
  16. if($worker_user)
  17. {
  18. $user_info = posix_getpwnam($worker_user);
  19. return !empty($user_info);
  20. }
  21. }
  22. /**
  23. * 检查扩展支持情况
  24. * @return void
  25. */
  26. public static function checkExtension()
  27. {
  28. // 扩展名=>是否是必须
  29. $need_map = array(
  30. 'posix' => true,
  31. 'pcntl' => true,
  32. 'sysvshm' => false,
  33. 'sysvmsg' => false,
  34. 'libevent' => false,
  35. 'ev' => false,
  36. 'uv' => false,
  37. 'proctitle' => false,
  38. );
  39. // 检查每个扩展支持情况
  40. echo "----------------------EXTENSION--------------------\n";
  41. $pad_length = 26;
  42. foreach($need_map as $ext_name=>$must_required)
  43. {
  44. $suport = extension_loaded($ext_name);
  45. if($must_required && !$suport)
  46. {
  47. \WORKERMAN\Core\Master::notice($ext_name. " [NOT SUPORT BUT REQUIRED] \tYou have to compile CLI version of PHP with --enable-{$ext_name} \tServer start fail");
  48. exit($ext_name. " \033[31;40m [NOT SUPORT BUT REQUIRED] \033[0m\n\n\033[31;40mYou have to compile CLI version of PHP with --enable-{$ext_name} \033[0m\n\n\033[31;40mServer start fail\033[0m\n\n");
  49. }
  50. // 支持扩展
  51. if($suport)
  52. {
  53. echo str_pad($ext_name, $pad_length), "\033[32;40m [OK] \033[0m\n";
  54. }
  55. // 不支持
  56. else
  57. {
  58. // ev uv inotify不是必须
  59. if('ev' == $ext_name || 'uv' == $ext_name || 'proctitle' == $ext_name)
  60. {
  61. continue;
  62. }
  63. echo str_pad($ext_name, $pad_length), "\033[33;40m [NOT SUPORT] \033[0m\n";
  64. }
  65. }
  66. }
  67. /**
  68. * 检查禁用的函数
  69. * @return void
  70. */
  71. public static function checkDisableFunction()
  72. {
  73. // 可能禁用的函数
  74. $check_func_map = array(
  75. 'stream_socket_server',
  76. 'stream_socket_client',
  77. 'pcntl_signal_dispatch',
  78. );
  79. if($disable_func_string = ini_get("disable_functions"))
  80. {
  81. $disable_func_map = array_flip(explode(',', $disable_func_string));
  82. }
  83. // 遍历查看是否有禁用的函数
  84. foreach($check_func_map as $func)
  85. {
  86. if(isset($disable_func_map[$func]))
  87. {
  88. \WORKERMAN\Core\Master::notice("Function $func may be disabled\tPlease check disable_functions in php.ini \t Server start fail");
  89. exit("\n\033[31;40mFunction $func may be disabled\nPlease check disable_functions in php.ini\033[0m\n\n\033[31;40mServer start fail\033[0m\n\n");
  90. }
  91. }
  92. }
  93. /**
  94. * 检查worker配置、worker语法错误等
  95. * @return void
  96. */
  97. public static function checkWorkersConfig()
  98. {
  99. $pad_length = 26;
  100. $total_worker_count = 0;
  101. // 检查worker 是否有语法错误
  102. echo "----------------------WORKERS--------------------\n";
  103. foreach (Config::get('workers') as $worker_name=>$config)
  104. {
  105. if(isset($config['socket']))
  106. {
  107. // 端口、协议、进程数等信息
  108. if(empty($config['socket']['port']))
  109. {
  110. \WORKERMAN\Core\Master::notice(str_pad($worker_name, $pad_length)." [port not set] \t Server start fail");
  111. exit(str_pad($worker_name, $pad_length)."\033[31;40m [port not set] \033[0m\n\n\033[31;40mServer start fail\033[0m\n");
  112. }
  113. if(empty($config['socket']['protocol']))
  114. {
  115. \WORKERMAN\Core\Master::notice(str_pad($worker_name, $pad_length)." [protocol not set]\tServer start fail");
  116. exit(str_pad($worker_name, $pad_length)."\033[31;40m [protocol not set]\033[0m\n\n\033[31;40mServer start fail\033[0m\n");
  117. }
  118. }
  119. if(empty($config['children_count']))
  120. {
  121. \WORKERMAN\Core\Master::notice(str_pad($worker_name, $pad_length)." [children_count not set]\tServer start fail");
  122. exit(str_pad($worker_name, $pad_length)."\033[31;40m [children_count not set]\033[0m\n\n\033[31;40mServer start fail\033[0m\n");
  123. }
  124. $total_worker_count += $config['children_count'];
  125. // 语法检查
  126. if(0 != self::checkSyntaxError(WORKERMAN_ROOT_DIR . "Workers/$worker_name.php", $worker_name))
  127. {
  128. unset(Config::instance()->config['workers'][$worker_name]);
  129. \WORKERMAN\Core\Master::notice("$worker_name has Fatal Err");
  130. echo str_pad($worker_name, $pad_length),"\033[31;40m [Fatal Err] \033[0m\n";
  131. continue;
  132. }
  133. if(isset($config['user']))
  134. {
  135. $worker_user = $config['user'];
  136. if(!self::checkWorkerUserName($worker_user))
  137. {
  138. echo str_pad($worker_name, $pad_length),"\033[31;40m [FAIL] \033[0m\n";
  139. \WORKERMAN\Core\Master::notice("Can not run $worker_name processes as user $worker_user , User $worker_user not exists\tServer start fail");
  140. exit("\n\033[31;40mCan not run $worker_name processes as user $worker_user , User $worker_user not exists\033[0m\n\n\033[31;40mServer start fail\033[0m\n\n");
  141. }
  142. }
  143. echo str_pad($worker_name, $pad_length),"\033[32;40m [OK] \033[0m\n";
  144. }
  145. if($total_worker_count > \WORKERMAN\Core\Master::SERVER_MAX_WORKER_COUNT)
  146. {
  147. \WORKERMAN\Core\Master::notice("Number of worker processes can not be more than " . \WORKERMAN\Core\Master::SERVER_MAX_WORKER_COUNT . ".\tPlease check children_count in " . WORKERMAN_ROOT_DIR . "config/main.php\tServer start fail");
  148. exit("\n\033[31;40mNumber of worker processes can not be more than " . \WORKERMAN\Core\Master::SERVER_MAX_WORKER_COUNT . ".\nPlease check children_count in " . WORKERMAN_ROOT_DIR . "config/main.php\033[0m\n\n\033[31;40mServer start fail\033[0m\n");
  149. }
  150. echo "-------------------------------------------------\n";
  151. }
  152. /**
  153. * 检查worker文件是否有语法错误
  154. * @param string $worker_name
  155. * @return int 0:无语法错误 其它:可能有语法错误
  156. */
  157. public static function checkSyntaxError($file, $class_name = null)
  158. {
  159. $pid = pcntl_fork();
  160. // 父进程
  161. if($pid > 0)
  162. {
  163. // 退出状态不为0说明可能有语法错误
  164. $pid = pcntl_wait($status);
  165. return $status;
  166. }
  167. // 子进程
  168. elseif($pid == 0)
  169. {
  170. // 载入对应worker
  171. require_once $file;
  172. if($class_name && !class_exists($class_name))
  173. {
  174. throw new \Exception("Class $class_name not exists");
  175. }
  176. exit(0);
  177. }
  178. }
  179. /**
  180. * 检查打开文件限制
  181. * @return void
  182. */
  183. public static function checkLimit()
  184. {
  185. if($limit_info = posix_getrlimit())
  186. {
  187. if('unlimited' != $limit_info['soft openfiles'] && $limit_info['soft openfiles'] < \WORKERMAN\Core\Master::MIN_SOFT_OPEN_FILES)
  188. {
  189. echo "Notice : Soft open files now is {$limit_info['soft openfiles']}, We recommend greater than " . \WORKERMAN\Core\Master::MIN_SOFT_OPEN_FILES . "\n";
  190. }
  191. if('unlimited' != $limit_info['hard filesize'] && $limit_info['hard filesize'] < \WORKERMAN\Core\Master::MIN_SOFT_OPEN_FILES)
  192. {
  193. echo "Notice : Hard open files now is {$limit_info['hard filesize']}, We recommend greater than " . \WORKERMAN\Core\Master::MIN_HARD_OPEN_FILES . "\n";
  194. }
  195. }
  196. }
  197. /**
  198. * 检查配置的pid文件是否可写
  199. * @return void
  200. */
  201. public static function checkPidFile()
  202. {
  203. // 已经有进程pid可能server已经启动
  204. if(@file_get_contents(WORKERMAN_PID_FILE))
  205. {
  206. \WORKERMAN\Core\Master::notice("Server already started", true);
  207. exit;
  208. }
  209. if(is_dir(WORKERMAN_PID_FILE))
  210. {
  211. exit("\n\033[31;40mpid-file ".WORKERMAN_PID_FILE." is Directory\033[0m\n\n\033[31;40mServer start failed\033[0m\n\n");
  212. }
  213. $pid_dir = dirname(WORKERMAN_PID_FILE);
  214. if(!is_dir($pid_dir))
  215. {
  216. if(!mkdir($pid_dir, true))
  217. {
  218. exit("Create dir $pid_dir fail\n");
  219. }
  220. }
  221. if(!is_writeable($pid_dir))
  222. {
  223. exit("\n\033[31;40mYou should start the server as root\033[0m\n\n\033[31;40mServer start failed\033[0m\n\n");
  224. }
  225. }
  226. }