1<?php 2 3const WORKER_ARGV_VALUE = 'RUN_WORKER'; 4 5function phpt_notify() 6{ 7 ServerClientTestCase::getInstance()->notify(); 8} 9 10function phpt_wait() 11{ 12 ServerClientTestCase::getInstance()->wait(); 13} 14 15/** 16 * This is a singleton to let the wait/notify functions work 17 * I know it's horrible, but it's a means to an end 18 */ 19class ServerClientTestCase 20{ 21 private $isWorker = false; 22 23 private $workerHandle; 24 25 private $workerStdIn; 26 27 private $workerStdOut; 28 29 private static $instance; 30 31 public static function getInstance($isWorker = false) 32 { 33 if (!isset(self::$instance)) { 34 self::$instance = new self($isWorker); 35 } 36 37 return self::$instance; 38 } 39 40 public function __construct($isWorker = false) 41 { 42 if (!isset(self::$instance)) { 43 self::$instance = $this; 44 } 45 46 $this->isWorker = $isWorker; 47 } 48 49 private function spawnWorkerProcess($code) 50 { 51 if (defined("PHP_WINDOWS_VERSION_MAJOR")) { 52 $ini = php_ini_loaded_file(); 53 $cmd = sprintf('%s %s "%s" %s', PHP_BINARY, $ini ? "-n -c $ini" : "", __FILE__, WORKER_ARGV_VALUE); 54 } else { 55 $cmd = sprintf('%s "%s" %s', PHP_BINARY, __FILE__, WORKER_ARGV_VALUE); 56 } 57 $this->workerHandle = proc_open($cmd, [['pipe', 'r'], ['pipe', 'w'], STDERR], $pipes); 58 $this->workerStdIn = $pipes[0]; 59 $this->workerStdOut = $pipes[1]; 60 61 fwrite($this->workerStdIn, $code . "\n---\n"); 62 } 63 64 private function cleanupWorkerProcess() 65 { 66 fclose($this->workerStdIn); 67 fclose($this->workerStdOut); 68 proc_close($this->workerHandle); 69 } 70 71 private function stripPhpTagsFromCode($code) 72 { 73 return preg_replace('/^\s*<\?(?:php)?|\?>\s*$/i', '', $code); 74 } 75 76 public function runWorker() 77 { 78 $code = ''; 79 80 while (1) { 81 $line = fgets(STDIN); 82 83 if (trim($line) === "---") { 84 break; 85 } 86 87 $code .= $line; 88 } 89 90 eval($code); 91 } 92 93 public function run($proc1Code, $proc2Code) 94 { 95 $this->spawnWorkerProcess($this->stripPhpTagsFromCode($proc2Code)); 96 eval($this->stripPhpTagsFromCode($proc1Code)); 97 $this->cleanupWorkerProcess(); 98 } 99 100 public function wait() 101 { 102 fgets($this->isWorker ? STDIN : $this->workerStdOut); 103 } 104 105 public function notify() 106 { 107 fwrite($this->isWorker ? STDOUT : $this->workerStdIn, "\n"); 108 } 109} 110 111if (isset($argv[1]) && $argv[1] === WORKER_ARGV_VALUE) { 112 ServerClientTestCase::getInstance(true)->runWorker(); 113} 114