&reftitle.examples; Простой клиент HTTP input; //$bev->getInput(); //$pos = $input->search("TTP"); $pos = $bev->input->search("TTP"); while (($n = $bev->input->remove($buf, 1024)) > 0) { echo $buf; } } // Функция обратного вызова обработки события function eventcb($bev, $events, $base) { if ($events & EventBufferEvent::CONNECTED) { echo "Соединение установлено.\n"; } elseif ($events & (EventBufferEvent::ERROR | EventBufferEvent::EOF)) { if ($events & EventBufferEvent::ERROR) { echo "Ошибка DNS: ", $bev->getDnsErrorString(), PHP_EOL; } echo "Закрываем соединение\n"; $base->exit(); exit("Готово\n"); } } if ($argc != 3) { echo <<setCallbacks("readcb", /* writecb */ NULL, "eventcb", $base); $bev->enable(Event::READ | Event::WRITE); $output = $bev->output; //$bev->getOutput(); if (!$output->add( "GET {$argv[2]} HTTP/1.0\r\n". "Host: {$argv[1]}\r\n". "Connection: Close\r\n\r\n" )) { exit("Ошибка добавления запроса в буфер вывода\n"); } if (!$bev->connectHost($dns_base, $argv[1], 80, EventUtil::AF_UNSPEC)) { exit("Невозможно установить соединение с {$argv[1]}\n"); } $base->dispatch(); ?> ]]> &example.outputs.similar; 301 Moved

301 Moved

The document has moved here. Закрываем соединение Готово ]]>
HTTP клиент с асинхронным запросом к DNS getInput(); while (($n = $input->remove($buf, 1024)) > 0) { echo $buf; } } // Функция обратного вызова обработки события function eventcb($bev, $events, $base) { if ($events & EventBufferEvent::CONNECTED) { echo "Соединение установлено.\n"; } elseif ($events & (EventBufferEvent::ERROR | EventBufferEvent::EOF)) { if ($events & EventBufferEvent::ERROR) { echo "Ошибка DNS: ", $bev->getDnsErrorString(), PHP_EOL; } echo "Закрываем соединение\n"; $base->exit(); exit("Готово\n"); } } $base = new EventBase(); echo "step 1\n"; $bev = new EventBufferEvent($base, /* используем внутренний сокет*/ NULL, EventBufferEvent::OPT_CLOSE_ON_FREE | EventBufferEvent::OPT_DEFER_CALLBACKS); if (!$bev) { exit("Ошибка создания сокета bufferevent\n"); } echo "step 2\n"; $bev->setCallbacks("readcb", /* writecb */ NULL, "eventcb", $base); $bev->enable(Event::READ | Event::WRITE); echo "step 3\n"; // Посылаем запрос $output = $bev->getOutput(); if (!$output->add( "GET /index.cphp HTTP/1.0\r\n". "Connection: Close\r\n\r\n" )) { exit("Ошибка добавления запроса в буфер вывода\n"); } /* Синхронно соединяемся с хостом. Мы знаем IP и не нуждаемся в запросе к DNS. */ if (!$bev->connect("127.0.0.1:80")) { exit("Не удалось установить соединение\n"); } // Обрабатываем ожидающие события $base->dispatch(); ?> ]]> Эхо-сервер bev->free(); } public function __construct($base, $fd) { $this->base = $base; $this->bev = new EventBufferEvent($base, $fd, EventBufferEvent::OPT_CLOSE_ON_FREE); $this->bev->setCallbacks(array($this, "echoReadCallback"), NULL, array($this, "echoEventCallback"), NULL); if (!$this->bev->enable(Event::READ)) { echo "Не удалось разрешить чтение (READ)\n"; return; } } public function echoReadCallback($bev, $ctx) { // Копируем все данные из буфера ввода в буфер вывода // Вариант #1 $bev->output->addBuffer($bev->input); /* Вариант #2 */ /* $input = $bev->getInput(); $output = $bev->getOutput(); $output->addBuffer($input); */ } public function echoEventCallback($bev, $events, $ctx) { if ($events & EventBufferEvent::ERROR) { echo "Ошибка bufferevent\n"; } if ($events & (EventBufferEvent::EOF | EventBufferEvent::ERROR)) { //$bev->free(); $this->__destruct(); } } } class MyListener { public $base, $listener, $socket; private $conn = array(); public function __destruct() { foreach ($this->conn as &$c) $c = NULL; } public function __construct($port) { $this->base = new EventBase(); if (!$this->base) { echo "Не удаётся создать EventBase"; exit(1); } // Вариант #1 /* $this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP); if (!socket_bind($this->socket, '0.0.0.0', $port)) { echo "Невозможно назначить сокет\n"; exit(1); } $this->listener = new EventListener($this->base, array($this, "acceptConnCallback"), $this->base, EventListener::OPT_CLOSE_ON_FREE | EventListener::OPT_REUSEABLE, -1, $this->socket); */ // Вариант #2 $this->listener = new EventListener($this->base, array($this, "acceptConnCallback"), $this->base, EventListener::OPT_CLOSE_ON_FREE | EventListener::OPT_REUSEABLE, -1, "0.0.0.0:$port"); if (!$this->listener) { echo "Невозможно создать слушателя"; exit(1); } $this->listener->setErrorCallback(array($this, "accept_error_cb")); } public function dispatch() { $this->base->dispatch(); } // Эта функция обратного вызова будет вызвана, если в $bev есть данные для чтения public function acceptConnCallback($listener, $fd, $address, $ctx) { // У нас новое соединение! Настроим bufferevent для него. */ $base = $this->base; $this->conn[] = new MyListenerConnection($base, $fd); } public function accept_error_cb($listener, $ctx) { $base = $this->base; fprintf(STDERR, "Ошибка слушателя: %d (%s). " ."Аварийная остановка.\n", EventUtil::getLastSocketErrno(), EventUtil::getLastSocketError()); $base->exit(NULL); } } $port = 9808; if ($argc > 1) { $port = (int) $argv[1]; } if ($port <= 0 || $port > 65535) { exit("Некорректный порт"); } $l = new MyListener($port); $l->dispatch(); ?> ]]> SSL эхо-сервер port = $port; $this->ctx = $this->init_ssl(); if (!$this->ctx) { exit("Невозможно создать контекст SSL\n"); } $this->base = new EventBase(); if (!$this->base) { exit("Невозможно создать EventBase\n"); } $this->listener = new EventListener($this->base, array($this, "ssl_accept_cb"), $this->ctx, EventListener::OPT_CLOSE_ON_FREE | EventListener::OPT_REUSEABLE, -1, "$host:$port"); if (!$this->listener) { exit("невозможно создать слушателя\n"); } $this->listener->setErrorCallback(array($this, "accept_error_cb")); } function dispatch() { $this->base->dispatch(); } // Эта функция обратного вызова будет вызвана, если в $bev есть данные для чтения function ssl_read_cb($bev, $ctx) { $in = $bev->input; //$bev->getInput(); printf("Received %zu bytes\n", $in->length); printf("----- data ----\n"); printf("%ld:\t%s\n", (int) $in->length, $in->pullup(-1)); $bev->writeBuffer($in); } // Эта функция обратного вызова будет вызвана, если на слушателя придёт событие, // например если закроется соединение или произойдёт ошибка function ssl_event_cb($bev, $events, $ctx) { if ($events & EventBufferEvent::ERROR) { // Извлекаем ошибку из стека ошибок SSL while ($err = $bev->sslError()) { fprintf(STDERR, "Ошибка bufferevent: %s.\n", $err); } } if ($events & (EventBufferEvent::EOF | EventBufferEvent::ERROR)) { $bev->free(); } } // Эта функция обратного вызова будет вызвана, когда клиент примет новое соединение function ssl_accept_cb($listener, $fd, $address, $ctx) { // У нас новое соединение! Настроим bufferevent для него. $this->bev = EventBufferEvent::sslSocket($this->base, $fd, $this->ctx, EventBufferEvent::SSL_ACCEPTING, EventBufferEvent::OPT_CLOSE_ON_FREE); if (!$this->bev) { echo "Failed creating ssl buffer\n"; $this->base->exit(NULL); exit(1); } $this->bev->enable(Event::READ); $this->bev->setCallbacks(array($this, "ssl_read_cb"), NULL, array($this, "ssl_event_cb"), NULL); } // Эта функция обратного вызова будет вызвана, если не удастся создать новое соединение function accept_error_cb($listener, $ctx) { fprintf(STDERR, "Ошибка слушателя: %d (%s). " ."Shutting down.\n", EventUtil::getLastSocketErrno(), EventUtil::getLastSocketError()); $this->base->exit(NULL); } // Инициализируем структуры SSL, создаём EventSslContext // Опционально создаём самоподписанный сертификат function init_ssl() { // Нам *необходима* энтропия. Иначе в криптографии нет смысла. if (!EventUtil::sslRandPoll()) { exit("EventUtil::sslRandPoll failed\n"); } $local_cert = __DIR__."/cert.pem"; $local_pk = __DIR__."/privkey.pem"; if (!file_exists($local_cert) || !file_exists($local_pk)) { echo "Невозможно прочитать $local_cert или $local_pk file. Для генерации ключа\n", "и самоподписанного сертификата, запустите:\n", " openssl genrsa -out $local_pk 2048\n", " openssl req -new -key $local_pk -out cert.req\n", " openssl x509 -req -days 365 -in cert.req -signkey $local_pk -out $local_cert\n"; return FALSE; } $ctx = new EventSslContext(EventSslContext::SSLv3_SERVER_METHOD, array ( EventSslContext::OPT_LOCAL_CERT => $local_cert, EventSslContext::OPT_LOCAL_PK => $local_pk, //EventSslContext::OPT_PASSPHRASE => "echo server", EventSslContext::OPT_VERIFY_PEER => true, EventSslContext::OPT_ALLOW_SELF_SIGNED => false, )); return $ctx; } } // Разрешаем переопределение порта $port = 9999; if ($argc > 1) { $port = (int) $argv[1]; } if ($port <= 0 || $port > 65535) { exit("Некорректный порт\n"); } $l = new MySslEchoServer($port); $l->dispatch(); ?> ]]> Обработчик сигналов base = $base; } function eventSighandler($no, $c) { echo "Пойман сигнал $no\n"; event_base_loopexit($c->base); } } $base = event_base_new(); $c = new MyEventSignal($base); $no = SIGTERM; $ev = evsignal_new($base, $no, array($c,'eventSighandler'), $c); evsignal_add($ev); event_base_loop($base); ?> ]]> Использование цикла libevent для обработки запросов модуля `eio' stop(); }, $base); echo "step 3\n"; $event->add(); echo "step 4\n"; $base->dispatch(); echo "Готово\n"; ?> ]]> Разное avoidMethod("select")) { echo "Метод 'select' будет игнорироваться\n"; } // Создаём event_base связанный с конфигурацией $base = new EventBase($cfg); echo "Используется событийный метод: ", $base->getMethod(), PHP_EOL; echo "Способы:\n"; $features = $base->getFeatures(); ($features & EventConfig::FEATURE_ET) and print "ET — одноразовое срабатывание при пересечении порога (edge-triggered IO)\n"; ($features & EventConfig::FEATURE_O1) and print "O1 — операции добавления/удаления событий со сложностью O(1)\n"; ($features & EventConfig::FEATURE_FDS) and print "FDS — обычные дескрипторы файлов, а не только сокеты\n"; // Запрашиваем способ FDS if ($cfg->requireFeatures(EventConfig::FEATURE_FDS)) { echo "Запрошен способ FDS\n"; $base = new EventBase($cfg); ($base->getFeatures() & EventConfig::FEATURE_FDS) and print "FDS — обычные дескрипторы файлов, а не только сокеты\n"; } /* }}} */ /* {{{ Base */ $base = new EventBase(); $event = new Event($base, STDIN, Event::READ | Event::PERSIST, function ($fd, $events, $arg) { static $max_iterations = 0; if (++$max_iterations >= 5) { /* выход после 5 итераций с паузами в 2.33 секунды */ echo "Останавливаемся...\n"; $arg[0]->exit(2.33); } echo fgets($fd); }, array (&$base)); $event->add(); $base->loop(); /* Base }}} */ ?> ]]> Простой HTTP-сервер = $max_requests) { echo "Счётчик запросов достиг максимума $max_requests. Выходим\n"; exit(); } echo __METHOD__, " метод\n"; echo "запрос:"; var_dump($req); echo "данные:"; var_dump($data); echo "\n===== DUMP =====\n"; echo "Команда:", $req->getCommand(), PHP_EOL; echo "URI:", $req->getUri(), PHP_EOL; echo "Входящие заголовки:"; var_dump($req->getInputHeaders()); echo "Исходящие заголовки:"; var_dump($req->getOutputHeaders()); echo "\n >> Посылаем ответ ..."; $req->sendReply(200, "OK"); echo "OK\n"; echo "\n >> Читаем входной буфер ...\n"; $buf = $req->getInputBuffer(); while ($s = $buf->readLine(EventBuffer::EOL_ANY)) { echo $s, PHP_EOL; } echo "В буфере больше нет данных\n"; } function _http_about($req) { echo __METHOD__, PHP_EOL; echo "URI: ", $req->getUri(), PHP_EOL; echo "\n >> Посылаем ответ ..."; $req->sendReply(200, "OK"); echo "OK\n"; } function _http_default($req, $data) { echo __METHOD__, PHP_EOL; echo "URI: ", $req->getUri(), PHP_EOL; echo "\n >> Посылаем ответ ..."; $req->sendReply(200, "OK"); echo "OK\n"; } $port = 8010; if ($argc > 1) { $port = (int) $argv[1]; } if ($port <= 0 || $port > 65535) { exit("Некорректный порт"); } $base = new EventBase(); $http = new EventHttp($base); $http->setAllowedMethods(EventHttpRequest::CMD_GET | EventHttpRequest::CMD_POST); $http->setCallback("/dump", "_http_dump", array(4, 8)); $http->setCallback("/about", "_http_about"); $http->setDefaultCallback("_http_default", "custom data value"); $http->bind("0.0.0.0", 8010); $base->loop(); ?> ]]> &example.outputs.similar; Простой HTTPS-сервер = $max_requests) { echo "Счётчик запросов достиг максимума $max_requests. Выходим\n"; exit(); } echo __METHOD__, " called\n"; echo "запрос:"; var_dump($req); echo "данные:"; var_dump($data); echo "\n===== DUMP =====\n"; echo "Команда:", $req->getCommand(), PHP_EOL; echo "URI:", $req->getUri(), PHP_EOL; echo "Входящие заголовки:"; var_dump($req->getInputHeaders()); echo "Исходящие заголовки:"; var_dump($req->getOutputHeaders()); echo "\n >> Отправляем ответ ..."; $req->sendReply(200, "OK"); echo "OK\n"; $buf = $req->getInputBuffer(); echo "\n >> Читаем входящий буфер (", $buf->length, ") ...\n"; while ($s = $buf->read(1024)) { echo $s; } echo "\nВ буфере больше нет данных\n"; } function _http_about($req) { echo __METHOD__, PHP_EOL; echo "URI: ", $req->getUri(), PHP_EOL; echo "\n >> Отправляем ответ ..."; $req->sendReply(200, "OK"); echo "OK\n"; } function _http_default($req, $data) { echo __METHOD__, PHP_EOL; echo "URI: ", $req->getUri(), PHP_EOL; echo "\n >> Отправляем ответ ..."; $req->sendReply(200, "OK"); echo "OK\n"; } function _http_400($req) { $req->sendError(400); } function _init_ssl() { $local_cert = __DIR__."/ssl-echo-server/cert.pem"; $local_pk = __DIR__."/ssl-echo-server/privkey.pem"; $ctx = new EventSslContext(EventSslContext::SSLv3_SERVER_METHOD, array ( EventSslContext::OPT_LOCAL_CERT => $local_cert, EventSslContext::OPT_LOCAL_PK => $local_pk, //EventSslContext::OPT_PASSPHRASE => "test", EventSslContext::OPT_ALLOW_SELF_SIGNED => true, )); return $ctx; } $port = 9999; if ($argc > 1) { $port = (int) $argv[1]; } if ($port <= 0 || $port > 65535) { exit("Некорректный порт"); } $ip = '0.0.0.0'; $base = new EventBase(); $ctx = _init_ssl(); $http = new EventHttp($base, $ctx); $http->setAllowedMethods(EventHttpRequest::CMD_GET | EventHttpRequest::CMD_POST); $http->setCallback("/dump", "_http_dump", array(4, 8)); $http->setCallback("/about", "_http_about"); $http->setCallback("/err400", "_http_400"); $http->setDefaultCallback("_http_default", "custom data value"); $http->bind($ip, $port); $base->dispatch(); ]]> OpenSSL соединение getResponseCode(); if ($response_code == 0) { echo "В соединении отказано\n"; } elseif ($response_code != 200) { echo "Неожиданный ответ: $response_code\n"; } else { echo "Соединение успешно: $response_code\n"; $buf = $req->getInputBuffer(); echo "Body:\n"; while ($s = $buf->readLine(EventBuffer::EOL_ANY)) { echo $s, PHP_EOL; } } } $base->exit(NULL); } function _init_ssl() { $ctx = new EventSslContext(EventSslContext::SSLv3_CLIENT_METHOD, array ()); return $ctx; } // Разрешаем переопределять порт $port = 9999; if ($argc > 1) { $port = (int) $argv[1]; } if ($port <= 0 || $port > 65535) { exit("Некорректный порт\n"); } $host = '127.0.0.1'; $ctx = _init_ssl(); if (!$ctx) { trigger_error("Не удалось создать контекст SSL", E_USER_ERROR); } $base = new EventBase(); if (!$base) { trigger_error("Не удалось инициализировать обработчик событий", E_USER_ERROR); } $conn = new EventHttpConnection($base, NULL, $host, $port, $ctx); $conn->setTimeout(50); $req = new EventHttpRequest("_request_handler", $base); $req->addHeader("Host", $host, EventHttpRequest::OUTPUT_HEADER); $buf = $req->getOutputBuffer(); $buf->add("HTML TEST"); //$req->addHeader("Content-Length", $buf->length, EventHttpRequest::OUTPUT_HEADER); //$req->addHeader("Connection", "close", EventHttpRequest::OUTPUT_HEADER); $conn->makeRequest($req, EventHttpRequest::CMD_POST, "/dump"); $base->dispatch(); echo "END\n"; ?> ]]> Пример использования <function>EventHttpConnection::makeRequest</function> getResponseCode(); if ($response_code == 0) { echo "В соединении отказано\n"; } elseif ($response_code != 200) { echo "Неожиданный ответ: $response_code\n"; } else { echo "Успешное соединение: $response_code\n"; $buf = $req->getInputBuffer(); echo "Данные:\n"; while ($s = $buf->readLine(EventBuffer::EOL_ANY)) { echo $s, PHP_EOL; } } } $base->exit(NULL); } $address = "127.0.0.1"; $port = 80; $base = new EventBase(); $conn = new EventHttpConnection($base, NULL, $address, $port); $conn->setTimeout(5); $req = new EventHttpRequest("_request_handler", $base); $req->addHeader("Host", $address, EventHttpRequest::OUTPUT_HEADER); $req->addHeader("Content-Length", "0", EventHttpRequest::OUTPUT_HEADER); $conn->makeRequest($req, EventHttpRequest::CMD_GET, "/index.cphp"); $base->loop(); ?> ]]> &example.outputs.similar; Слушатель соединений на базе сокетов UNIX bev) { $this->bev->free(); } } public function __construct($base, $fd) { $this->base = $base; $this->bev = new EventBufferEvent($base, $fd, EventBufferEvent::OPT_CLOSE_ON_FREE); $this->bev->setCallbacks(array($this, "echoReadCallback"), NULL, array($this, "echoEventCallback"), NULL); if (!$this->bev->enable(Event::READ)) { echo "Не удалось разрешить чтение (READ)\n"; return; } } public function echoReadCallback($bev, $ctx) { // Копируем все данные из входящего буфера в исходящий буфер $bev->output->addBuffer($bev->input); } public function echoEventCallback($bev, $events, $ctx) { if ($events & EventBufferEvent::ERROR) { echo "Ошибка в bufferevent\n"; } if ($events & (EventBufferEvent::EOF | EventBufferEvent::ERROR)) { $bev->free(); $bev = NULL; } } } class MyListener { public $base, $listener, $socket; private $conn = array(); public function __destruct() { foreach ($this->conn as &$c) $c = NULL; } public function __construct($sock_path) { $this->base = new EventBase(); if (!$this->base) { echo "Не удаётся открыть обработчик ошибок"; exit(1); } if (file_exists($sock_path)) { unlink($sock_path); } $this->listener = new EventListener($this->base, array($this, "acceptConnCallback"), $this->base, EventListener::OPT_CLOSE_ON_FREE | EventListener::OPT_REUSEABLE, -1, "unix:$sock_path"); if (!$this->listener) { trigger_error("Невозможно создать слушатель", E_USER_ERROR); } $this->listener->setErrorCallback(array($this, "accept_error_cb")); } public function dispatch() { $this->base->dispatch(); } // Эта callback-функция будет запущена, когда в $bev появятся данные для чтения public function acceptConnCallback($listener, $fd, $address, $ctx) { // Появилось новое соединение! Настроем для него bufferevent. */ $base = $this->base; $this->conn[] = new MyListenerConnection($base, $fd); } public function accept_error_cb($listener, $ctx) { $base = $this->base; fprintf(STDERR, "Ошибка слушателя: %d (%s). " ."Shutting down.\n", EventUtil::getLastSocketErrno(), EventUtil::getLastSocketError()); $base->exit(NULL); } } if ($argc <= 1) { exit("Не указан сокет\n"); } $sock_path = $argv[1]; $l = new MyListener($sock_path); $l->dispatch(); ?> ]]> Простой SMTP-сервер * * Usage: * 1) Подготовим файлы сертификата cert.pem и приватного ключа privkey.pem. * 2) Запустим скрипт сервера * 3) Откроем TLS-соединение, например: * $ openssl s_client -connect localhost:25 -starttls smtp -crlf * 4) Протестируем команды, описанные в метода `cmd`. */ class Handler { public $domainName = FALSE; public $connections = []; public $buffers = []; public $maxRead = 256000; public function __construct() { $this->ctx = new EventSslContext(EventSslContext::SSLv3_SERVER_METHOD, [ EventSslContext::OPT_LOCAL_CERT => 'cert.pem', EventSslContext::OPT_LOCAL_PK => 'privkey.pem', //EventSslContext::OPT_PASSPHRASE => '', EventSslContext::OPT_VERIFY_PEER => false, // для корректного сертификата укажите true EventSslContext::OPT_ALLOW_SELF_SIGNED => true // для корректного сертификата укажите false ]); $this->base = new EventBase(); if (!$this->base) { exit("Не удалось открыть обработчик событий\n"); } if (!$this->listener = new EventListener($this->base, [$this, 'ev_accept'], $this->ctx, EventListener::OPT_CLOSE_ON_FREE | EventListener::OPT_REUSEABLE, -1, '0.0.0.0:25')) { exit("Невозможно создать слушателя\n"); } $this->listener->setErrorCallback([$this, 'ev_error']); $this->base->dispatch(); } public function ev_accept($listener, $fd, $address, $ctx) { static $id = 0; $id += 1; $this->connections[$id]['clientData'] = ''; $this->connections[$id]['cnx'] = new EventBufferEvent($this->base, $fd, EventBufferEvent::OPT_CLOSE_ON_FREE); if (!$this->connections[$id]['cnx']) { echo "Failed creating buffer\n"; $this->base->exit(NULL); exit(1); } $this->connections[$id]['cnx']->setCallbacks([$this, "ev_read"], NULL, [$this, 'ev_error'], $id); $this->connections[$id]['cnx']->enable(Event::READ | Event::WRITE); $this->ev_write($id, '220 '.$this->domainName." wazzzap?\r\n"); } function ev_error($listener, $ctx) { $errno = EventUtil::getLastSocketErrno(); fprintf(STDERR, "Ошибка слушателя: %d (%s). Аварийное завершение работы.\n", $errno, EventUtil::getLastSocketError()); if ($errno != 0) { $this->base->exit(NULL); exit(); } } public function ev_close($id) { $this->connections[$id]['cnx']->disable(Event::READ | Event::WRITE); unset($this->connections[$id]); } protected function ev_write($id, $string) { echo 'S('.$id.'): '.$string; $this->connections[$id]['cnx']->write($string); } public function ev_read($buffer, $id) { while($buffer->input->length > 0) { $this->connections[$id]['clientData'] .= $buffer->input->read($this->maxRead); $clientDataLen = strlen($this->connections[$id]['clientData']); if($this->connections[$id]['clientData'][$clientDataLen-1] == "\n" && $this->connections[$id]['clientData'][$clientDataLen-2] == "\r") { // удаляем все завершающие \r\n $line = substr($this->connections[$id]['clientData'], 0, strlen($this->connections[$id]['clientData']) - 2); $this->connections[$id]['clientData'] = ''; $this->cmd($buffer, $id, $line); } } } protected function cmd($buffer, $id, $line) { switch ($line) { case strncmp('EHLO ', $line, 4): $this->ev_write($id, "250-STARTTLS\r\n"); $this->ev_write($id, "250 OK ehlo\r\n"); break; case strncmp('HELO ', $line, 4): $this->ev_write($id, "250-STARTTLS\r\n"); $this->ev_write($id, "250 OK helo\r\n"); break; case strncmp('QUIT', $line, 3): $this->ev_write($id, "250 OK quit\r\n"); $this->ev_close($id); break; case strncmp('STARTTLS', $line, 3): $this->ev_write($id, "220 Ready to start TLS\r\n"); $this->connections[$id]['cnx'] = EventBufferEvent::sslFilter($this->base, $this->connections[$id]['cnx'], $this->ctx, EventBufferEvent::SSL_ACCEPTING, EventBufferEvent::OPT_CLOSE_ON_FREE); $this->connections[$id]['cnx']->setCallbacks([$this, "ev_read"], NULL, [$this, 'ev_error'], $id); $this->connections[$id]['cnx']->enable(Event::READ | Event::WRITE); break; default: echo 'неизвестная команда: '.$line."\n"; break; } } } new Handler(); ]]>