From 0b4938d6359f116f2574f1f989e84d91a9e9fba8 Mon Sep 17 00:00:00 2001 From: Krystian Duma Date: Wed, 17 Apr 2019 19:11:42 +0200 Subject: [PATCH] Refactoring --- .gitignore | 3 + class.lpd.php | 123 ---------- composer.json | 20 ++ composer.lock | 19 ++ example/class.lpr.php | 140 ----------- example/client-example.php | 36 +++ example/client.php | 10 - example/dump.txt | 71 ------ example/server-example.php | 24 ++ example/server.php | 10 - src/Client/Configuration.php | 93 +++++++ src/Client/DebugHandler/BasicDebugHandler.php | 34 +++ src/Client/Exceptions/InvalidJobException.php | 8 + src/Client/Exceptions/PrintErrorException.php | 8 + src/Client/Jobs/FileJob.php | 88 +++++++ src/Client/Jobs/JobInterface.php | 27 +++ src/Client/Jobs/TextJob.php | 75 ++++++ src/Client/PrintService.php | 117 +++++++++ src/DebugHandlerTrait.php | 38 +++ .../Exceptions/SocketErrorException.php | 10 + src/Server/Server.php | 226 ++++++++++++++++++ 21 files changed, 826 insertions(+), 354 deletions(-) create mode 100644 .gitignore delete mode 100644 class.lpd.php create mode 100644 composer.json create mode 100644 composer.lock delete mode 100644 example/class.lpr.php create mode 100644 example/client-example.php delete mode 100644 example/client.php delete mode 100644 example/dump.txt create mode 100644 example/server-example.php delete mode 100644 example/server.php create mode 100644 src/Client/Configuration.php create mode 100644 src/Client/DebugHandler/BasicDebugHandler.php create mode 100644 src/Client/Exceptions/InvalidJobException.php create mode 100644 src/Client/Exceptions/PrintErrorException.php create mode 100644 src/Client/Jobs/FileJob.php create mode 100644 src/Client/Jobs/JobInterface.php create mode 100644 src/Client/Jobs/TextJob.php create mode 100644 src/Client/PrintService.php create mode 100644 src/DebugHandlerTrait.php create mode 100644 src/Server/Exceptions/SocketErrorException.php create mode 100644 src/Server/Server.php diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..0bfef2a --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/vendor/ +/.idea +/example/dump.txt diff --git a/class.lpd.php b/class.lpd.php deleted file mode 100644 index dfb0e92..0000000 --- a/class.lpd.php +++ /dev/null @@ -1,123 +0,0 @@ -debg = $debg; - $this->call = $call; - - if(($this->sock = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) { - throw new Exception('socket_create() failed: reason: ' . socket_strerror(socket_last_error())); - } - if(socket_bind($this->sock, $addr, $port) === false) { - throw new Exception('socket_bind() failed: reason: ' . socket_strerror(socket_last_error($sock))); - } - if(socket_listen($this->sock, $maxc) === false) { - throw new Exception('socket_listen() failed: reason: ' . socket_strerror(socket_last_error($sock))); - } - if($start) { - $this->start(); - } - } - public function __destruct() { - @socket_close($this->sock); - } - public function start() { - do { - if(($msgsock = socket_accept($this->sock)) === false) { - throw new Exception('socket_accept() failed: reason: ' . socket_strerror(socket_last_error($sock))); - } - $this->debug('New client'); - $this->read_command($msgsock); - } - while(true); - } - - protected function read_command($msgsock, $receive_mode = false, $control_file = null) { - if(false === ($buff = socket_read($msgsock, 4096, PHP_NORMAL_READ))) { - throw new Exception('socket_read() failed: reason: ' . socket_strerror(socket_last_error($msgsock))); - } - $command = ord($buff[0]); - $arguments = preg_split('([\s]+)', substr($buff,1)); - $this->process_command($msgsock, $command, $arguments, $receive_mode, $control_file); - } - protected function read_bytes($msgsock, $bytes) { - $content = ''; - do { - if(false === ($buff = socket_read($msgsock, 1024, PHP_BINARY_READ))) { - throw new Exception('socket_read() failed: reason: ' . socket_strerror(socket_last_error($msgsock))); - } - $content .= $buff; - } while(mb_strlen($content, '8bit') < $bytes && $buff != ''); - return $content; - //return mb_substr($content, 0, $bytes, '8bit'); - } - protected function process_command($msgsock, $command, $arguments, $receive_mode, $control_file = null) { - $this->debug($command); - switch($command) { - case 1: - socket_write($msgsock, chr(0)); - socket_close($msgsock); - break; - case 2: - if(!$receive_mode) { - $receive_mode = true; - socket_write($msgsock, chr(0)); - $this->read_command($msgsock, $receive_mode); - } - else { - socket_write($msgsock, chr(0)); - $control_file = $this->read_bytes($msgsock, $arguments[0]); - socket_write($msgsock, chr(0)); - $this->read_command($msgsock, $receive_mode, $control_file); - } - break; - case 3: - if(!$receive_mode) { - socket_write($msgsock, chr(0)); - $this->read_command($msgsock, $receive_mode); - } - else { - socket_write($msgsock, chr(0)); - $data = $this->read_bytes($msgsock, $arguments[0]); - socket_write($msgsock, chr(0)); - socket_close($msgsock); - $this->process_data($data, $control_file); - } - break; - default: - socket_write($msgsock, chr(0)); - break; - } - } - protected function debug($msg) { - if($this->debg) { - echo $msg . "\r\n"; - } - } - protected function process_data($data, $control_file) { - $data = preg_split('(\n)', $data); - $dump = array(); - foreach($data as $row) { - $res = array(); - $row = preg_split('(\r)', $row); - foreach($row as $r) { - for($i = 0, $j = strlen($r); $i < $j; $i++) { - if(!isset($res[$i]) || $r[$i] !== ' ') { - $res[$i] = $r[$i]; - } - } - } - $dump[] = implode('',$res); - } - $dump = implode("\r\n", $dump); - $data = $dump; - - if($this->call && is_callable($this->call)) { - call_user_func($this->call, $data, $control_file); - } - } -} \ No newline at end of file diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..a98dc84 --- /dev/null +++ b/composer.json @@ -0,0 +1,20 @@ +{ + "name": "kduma/lpd", + "description": "LPD Client for PHP", + "type": "library", + "authors": [ + { + "name": "Krystian Duma", + "email": "git@krystian.duma.sh" + } + ], + "require": { + "ext-sockets": "*", + "ext-mbstring": "*" + }, + "autoload": { + "psr-4": { + "KDuma\\LPD\\": "src/" + } + } +} diff --git a/composer.lock b/composer.lock new file mode 100644 index 0000000..3b7f167 --- /dev/null +++ b/composer.lock @@ -0,0 +1,19 @@ +{ + "_readme": [ + "This file locks the dependencies of your project to a known state", + "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", + "This file is @generated automatically" + ], + "content-hash": "c3f5f8a2937d3378ca145d8d9e91159e", + "packages": [], + "packages-dev": [], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": [], + "prefer-stable": false, + "prefer-lowest": false, + "platform": { + "ext-sockets": "*" + }, + "platform-dev": [] +} diff --git a/example/class.lpr.php b/example/class.lpr.php deleted file mode 100644 index ad08daa..0000000 --- a/example/class.lpr.php +++ /dev/null @@ -1,140 +0,0 @@ -data = $data; - echo "Data set\n"; - } - public static function printerFactory($type){ - //Return a new instance of a printer driver of type $type. - if (include_once 'Drivers/' . $type . '.php') { - return new $type; - } else { - throw new Exception ('Driver not found: $type'); - } - } - public function getDebug(){ - return $this->debug; - } -} - -class PrintSendLPR extends PrintSend -{ - private $host = "localhost"; - private $port = "515"; - private $timeout = "20"; //20 secs - private $errNo; - private $errStr; - - public function __construct() { - parent::__construct(); - } - public function setPort($port){ - $this->port = $port; - echo "Port is ".$this->port."\n"; - } - public function setHost($host){ - $this->host = $host; - echo "Host is ".$this->host."\n"; - } - public function setTimeout($timeout){ - $this->timeout = $timeout; - } - public function getErrNo(){ - return $this->errNo; - } - - public function getErrStr(){ - return $this->errStr; - } - public function printJob($queue){ - //Private static function prints waiting jobs on the queue. - $this->printWaiting($queue); - - //Open a new connection to send the control file and data. - $stream = stream_socket_client("tcp://".$this->host.":".$this->port, $this->errNo, $this->errStr, $this->timeout); - if(!$stream){ - return $this->errNo." (".$this->errStr.")"; - } - else { - $job = self::getJobId();//Get a new id for this job - - //Set printer to receive file - fwrite($stream, chr(2).$queue."\n"); - echo "Confirmation of receive cmd:".ord(fread($stream, 1))."\n"; - - //Send Control file. - (isset($_SERVER['SERVER_NAME'])) ? $server = $_SERVER['SERVER_NAME'] : $server = "me";//Might be CLI and not have _SERVER - $ctrl = "H".$server."\nPphp\nfdfA".$job.$server."\n"; - fwrite($stream, chr(2).strlen($ctrl)." cfA".$job.$server."\n"); - echo "Confirmation of sending of control file cmd:".ord(fread($stream, 1))."\n"; - - fwrite($stream, $ctrl.chr(0)); //Write null to indicate end of stream - echo "Confirmation of sending of control file itself:".ord(fread($stream, 1))."\n"; - - if (is_readable($this->data)){ - //It's a filename, rather than just some ascii text that needs printing. Open and stream. - if (strstr(strtolower($_ENV["OS"]), "windows")){ - echo "Operating system is Windows\n"; - $data = fopen($this->data, "rb");//Force binary in Windows. - } else { - echo "Operating system is not Windows\n"; - $data = fopen($this->data, "r"); - } - fwrite($stream, chr(3).filesize($this->data)." dfA".$job.$server."\n"); - echo "Confirmation of sending receive data cmd:".ord(fread($stream, 1))."\n"; - - while(!feof($data)){ - fwrite($stream, fread($data, 8192)); - } - fwrite($stream, chr(0));//Write null to indicate end of stream - echo "Confirmation of sending data:".ord(fread($stream, 1))."\n"; - - fclose($data); - } - else { - //Send data string - fwrite($stream, chr(3).strlen($this->data)." dfA".$job.$server."\n"); - echo "Confirmation of sending receive data cmd:".ord(fread($stream, 1))."\n"; - fwrite($stream, $this->data.chr(0)); //Write null to indicate end of stream - echo "Confirmation of sending data:".ord(fread($stream, 1))."\n"; - } - } - - } - - public function interpret(){} - private function getJobId(){ - return "001"; - } - private function printWaiting($queue){ - $stream = stream_socket_client("tcp://".$this->host.":".$this->port, $this->errNo, $this->errStr, $this->timeout); - if (!$stream){ - return $this->errNo." (".$this->errStr.")"; - } else { - //Print any waiting jobs - fwrite($stream, chr(1).$queue."\n"); - echo "Confirmation of print waiting jobs cmd:"; - while(!feof($stream)){ - echo ord(fread($stream, 1)); - } - echo "\n"; - } - } -} diff --git a/example/client-example.php b/example/client-example.php new file mode 100644 index 0000000..8875e5a --- /dev/null +++ b/example/client-example.php @@ -0,0 +1,36 @@ +setDebugHandler($debug_handler); + +$jobs = [ + new TextJob("This is test!"), + new FileJob(__FILE__) +]; + +foreach ($jobs as $job) { + try { + $print_service->sendJob($job); + echo "Job Sent!\n"; + } catch (InvalidJobException | PrintErrorException $e) { + echo sprintf("Error occured: %s\n", $e->getMessage()); + } +} + +echo sprintf("\n--- DEBUG LOG ---\n\n%s", $debug_handler->getLog()); diff --git a/example/client.php b/example/client.php deleted file mode 100644 index 167b4ab..0000000 --- a/example/client.php +++ /dev/null @@ -1,10 +0,0 @@ -setHost("127.0.0.1"); -$lpr->setData("Some text to test."); -echo $lpr->printJob("test"); diff --git a/example/dump.txt b/example/dump.txt deleted file mode 100644 index 7e9e160..0000000 --- a/example/dump.txt +++ /dev/null @@ -1,71 +0,0 @@ - - - - Windows - Printer Test Page - Congratulations! - If you can read this information, you have correctly installed your - Generic / Text Only on ***. - The information below describes your printer driver and port - settings. - Submitted Time: 11:35:18 ÷. .3..2..2013 .ã. - Computer name: *** - Printer name: PHP test - Printer model: Generic / Text Only - Color support: No - Port name(s): 127.0.0.1:515 - Data format: TEXT - Share name: - Location: - Comment: - Driver name: UNIDRV.DLL - Data file: TTY.GPD - Config file: UNIDRVUI.DLL - Help file: UNIDRV.HLP - Driver version: 6.00 - Environment: Windows x64 - Additional files used by this driver: - C:\Windows\system32\spool\DRIVERS\x64\3\TTYRES.DLL - (6.1.7600.16385 (win7_rtm.090713-1255)) - C:\Windows\system32\spool\DRIVERS\x64\3\TTY.INI - C:\Windows\system32\spool\DRIVERS\x64\3\TTY.DLL - (6.1.7600.16385 (win7_rtm.090713-1255)) - C:\Windows\system32\spool\DRIVERS\x64\3\TTYUI.DLL - (6.1.7600.16385 (win7_rtm.090713-1255)) - C:\Windows\system32\spool\DRIVERS\x64\3\TTYUI.HLP - C:\Windows\system32\spool\DRIVERS\x64\3\UNIRES.DLL - (6.1.7600.16385 (win7_rtm.090713-1255)) - C:\Windows\system32\spool\DRIVERS\x64\3\STDNAMES.GPD - C:\Windows\system32\spool\DRIVERS\x64\3\STDDTYPE.GDL - C:\Windows\system32\spool\DRIVERS\x64\3\STDSCHEM.GDL - C:\Windows\system32\spool\DRIVERS\x64\3\STDSCHMX.GDL - This is the end of the printer test page. - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/example/server-example.php b/example/server-example.php new file mode 100644 index 0000000..a0d3cf4 --- /dev/null +++ b/example/server-example.php @@ -0,0 +1,24 @@ +setAddress('127.0.0.1') + ->setPort(Server::LPD_DEFAULT_PORT) + ->setMaxConnections(5) + ->setHandler(function ($data, $ctrl) { + echo $data; + file_put_contents(dirname(__FILE__) . '/dump.txt', $data); + }) + ->run(); + +} catch (Exception $e) { + echo sprintf("Error occured: %s", $e->getMessage()); +} diff --git a/example/server.php b/example/server.php deleted file mode 100644 index 90b62d1..0000000 --- a/example/server.php +++ /dev/null @@ -1,10 +0,0 @@ -port = $port; + $this->address = $address; + $this->queue = $queue; + $this->timeout = $timeout; + } + + /** + * @param string $address + * @param string $queue + * @param int $port + * @param int $timeout + * + * @return Configuration + */ + public static function make($address, $queue = self::DEFAULT_QUEUE_NAME, $port = self::LPD_DEFAULT_PORT, $timeout = self::ONE_MINUTE) + { + return new self($address, $queue, $port, $timeout); + } + + /** + * @return int + */ + public function getPort() + { + return $this->port; + } + + /** + * @return string + */ + public function getAddress() + { + return $this->address; + } + + /** + * @return string + */ + public function getQueue() + { + return $this->queue; + } + + /** + * @return string + */ + public function getTimeout() + { + return $this->timeout; + } +} \ No newline at end of file diff --git a/src/Client/DebugHandler/BasicDebugHandler.php b/src/Client/DebugHandler/BasicDebugHandler.php new file mode 100644 index 0000000..8d5567c --- /dev/null +++ b/src/Client/DebugHandler/BasicDebugHandler.php @@ -0,0 +1,34 @@ +messages[] = $message; + } + + public function clearLog() + { + $this->messages = []; + } + + /** + * @return string + */ + public function getLog() + { + return implode("\n", $this->messages); + } +} \ No newline at end of file diff --git a/src/Client/Exceptions/InvalidJobException.php b/src/Client/Exceptions/InvalidJobException.php new file mode 100644 index 0000000..65d245d --- /dev/null +++ b/src/Client/Exceptions/InvalidJobException.php @@ -0,0 +1,8 @@ +file_name = $file_name; + } + + /** + * @return string + */ + public function getFileName() + { + return $this->file_name; + } + + /** + * @return int + */ + public function getContentLength() + { + return filesize($this->file_name); + } + + /** + * @param resource $stream + * @param callable $debug + */ + public function streamContent($stream, $debug) + { + $handler = $this->getFileHandler($debug); + + while(!feof($handler)){ + fwrite($stream, fread($handler, 8192)); + } + + fclose($handler); + } + + /** + * @param callable $debug + * + * @return resource + */ + private function getFileHandler($debug) + { + if (strtoupper(substr(PHP_OS, 0, 3)) === 'WIN') { + $debug("Operating system is Windows"); + //Force binary in Windows. + return fopen($this->file_name, "rb"); + } + + $debug("Operating system is not Windows"); + return fopen($this->file_name, "r"); + } + + /** + * @param $error_message + * @param $error_number + * + * @return bool + */ + public function isValid(&$error_message, &$error_number) + { + if(is_readable($this->file_name)) + return true; + + $error_message = "File is not readable!"; + $error_number = 404; + + return false; + } +} \ No newline at end of file diff --git a/src/Client/Jobs/JobInterface.php b/src/Client/Jobs/JobInterface.php new file mode 100644 index 0000000..5b0f67f --- /dev/null +++ b/src/Client/Jobs/JobInterface.php @@ -0,0 +1,27 @@ +content = $content; + } + + /** + * @return string + */ + public function getContent() + { + return $this->content; + } + + /** + * @param string $content + */ + public function setContent($content) + { + $this->content = $content; + } + + /** + * @param string $content + */ + public function appdendContent($content) + { + $this->content .= $content; + } + + /** + * @return int + */ + public function getContentLength() + { + return strlen($this->content); + } + + /** + * @param resource $stream + * @param callable $debug + */ + public function streamContent($stream, $debug) + { + fwrite($stream, $this->getContent()); + } + + /** + * @param $error_message + * @param $error_number + * + * @return bool|string + */ + public function isValid(&$error_message, &$error_number) + { + return true; + } +} \ No newline at end of file diff --git a/src/Client/PrintService.php b/src/Client/PrintService.php new file mode 100644 index 0000000..b0e9d85 --- /dev/null +++ b/src/Client/PrintService.php @@ -0,0 +1,117 @@ +configuration = $configuration; + } + + /** + * @param JobInterface $job + * + * @return string + * @throws PrintErrorException + * @throws InvalidJobException + */ + public function sendJob(JobInterface $job){ + if(!$job->isValid($error_message, $error_number)) + throw new InvalidJobException($error_message, $error_number); + + //Private static function prints waiting jobs on the queue. + $this->printWaiting(); + + //Open a new connection to send the control file and data. + $stream = stream_socket_client( + sprintf("tcp://%s:%s", $this->configuration->getAddress(), $this->configuration->getPort()), + $error_number, + $error_message, + $this->configuration->getTimeout() + ); + + if (!$stream) + throw new PrintErrorException($error_message, $error_number); + + $jobId = self::getJobId(); + + //Set printer to receive file + fwrite($stream, sprintf("%s%s\n", chr(2), $this->configuration->getQueue())); + $this->debug("Confirmation of receive cmd:".ord(fread($stream, 1))); + + //Send Control file. + $server = $this->getServerName(); + $ctrl = sprintf("H%s\nPphp\nfdfA%s%s\n", $server, $jobId, $server); + fwrite($stream, sprintf("%s%s cfA%s%s\n", chr(2), strlen($ctrl), $jobId, $server)); + $this->debug("Confirmation of sending of control file cmd:".ord(fread($stream, 1))); + + fwrite($stream, sprintf("%s%s", $ctrl, chr(0))); //Write null to indicate end of stream + $this->debug("Confirmation of sending of control file itself:".ord(fread($stream, 1))); + + + + fwrite($stream, sprintf("%s%s dfA%s%s\n", chr(3), $job->getContentLength(), $jobId, $server)); + $this->debug("Confirmation of sending receive data cmd:".ord(fread($stream, 1))); + + $job->streamContent($stream, function ($message) { + $this->debug($message); + }); + + fwrite($stream, chr(0));//Write null to indicate end of stream + $this->debug("Confirmation of sending data:".ord(fread($stream, 1))); + } + + /** + * @throws PrintErrorException + */ + private function printWaiting(){ + $stream = stream_socket_client( + sprintf("tcp://%s:%s", $this->configuration->getAddress(), $this->configuration->getPort()), + $error_number, + $error_message, + $this->configuration->getTimeout() + ); + + if (!$stream) + throw new PrintErrorException($error_message, $error_number); + + //Print any waiting jobs + fwrite($stream, sprintf("%s%s\n", chr(1), $this->configuration->getQueue())); + while(!feof($stream)) + fread($stream, 1); + + } + + private static function getJobId(){ + return "001"; + } + + /** + * @return mixed|string + */ + private function getServerName() + { + return (isset($_SERVER['SERVER_NAME'])) ? $_SERVER['SERVER_NAME'] : "me"; + } + +} \ No newline at end of file diff --git a/src/DebugHandlerTrait.php b/src/DebugHandlerTrait.php new file mode 100644 index 0000000..2b0cda3 --- /dev/null +++ b/src/DebugHandlerTrait.php @@ -0,0 +1,38 @@ +debug_handler = $debug_handler; + + return $this; + } + + /** + * @param $message + */ + protected function debug($message) + { + if ($this->debug_handler) { + $handler = $this->debug_handler; + $handler($message); + } + } +} \ No newline at end of file diff --git a/src/Server/Exceptions/SocketErrorException.php b/src/Server/Exceptions/SocketErrorException.php new file mode 100644 index 0000000..636aeb7 --- /dev/null +++ b/src/Server/Exceptions/SocketErrorException.php @@ -0,0 +1,10 @@ +handler = $handler; + return $this; + } + + /** + * @param string $address + * + * @return Server + */ + public function setAddress(string $address): Server + { + $this->address = $address; + return $this; + } + + /** + * @param int $port + * + * @return Server + */ + public function setPort(int $port): Server + { + $this->port = $port; + return $this; + } + + /** + * @param int $max_connections + * + * @return Server + */ + public function setMaxConnections(int $max_connections): Server + { + $this->max_connections = $max_connections; + return $this; + } + + /** + * + */ + public function __destruct() + { + @socket_close($this->socket); + } + + /** + * @throws SocketErrorException + */ + public function run() + { + if (($this->socket = socket_create(AF_INET, SOCK_STREAM, SOL_TCP)) === false) { + throw new SocketErrorException('socket_create() failed: reason: ' . socket_strerror(socket_last_error())); + } + if (socket_bind($this->socket, $this->address, $this->port) === false) { + throw new SocketErrorException('socket_bind() failed: reason: ' . socket_strerror(socket_last_error($this->socket))); + } + if (socket_listen($this->socket, $this->max_connections) === false) { + throw new SocketErrorException('socket_listen() failed: reason: ' . socket_strerror(socket_last_error($this->socket))); + } + + do { + if (($msgsock = socket_accept($this->socket)) === false) { + throw new SocketErrorException('socket_accept() failed: reason: ' . socket_strerror(socket_last_error($this->socket))); + } + $this->debug('New client'); + $this->read_command($msgsock); + } while (true); + } + + /** + * @param $msgsock + * @param bool $receive_mode + * @param null $control_file + * + * @throws SocketErrorException + * @throws Exception + */ + protected function read_command($msgsock, $receive_mode = false, $control_file = null) + { + if (false === ($buff = socket_read($msgsock, 4096, PHP_NORMAL_READ))) { + throw new SocketErrorException('socket_read() failed: reason: ' . socket_strerror(socket_last_error($msgsock))); + } + $command = ord($buff[0]); + $arguments = preg_split('([\s]+)', substr($buff, 1)); + $this->process_command($msgsock, $command, $arguments, $receive_mode, $control_file); + } + + /** + * @param $msgsock + * @param $bytes + * + * @return string + * @throws SocketErrorException + */ + protected function read_bytes($msgsock, $bytes) + { + $content = ''; + do { + if (false === ($buff = socket_read($msgsock, 1024, PHP_BINARY_READ))) { + throw new SocketErrorException('socket_read() failed: reason: ' . socket_strerror(socket_last_error($msgsock))); + } + $content .= $buff; + } while (mb_strlen($content, '8bit') < $bytes && $buff != ''); + return $content; + } + + /** + * @param $msgsock + * @param $command + * @param $arguments + * @param $receive_mode + * @param null $control_file + * + * @throws Exception + */ + protected function process_command($msgsock, $command, $arguments, $receive_mode, $control_file = null) + { + $this->debug($command); + switch ($command) { + case 1: + socket_write($msgsock, chr(0)); + socket_close($msgsock); + break; + case 2: + if (!$receive_mode) { + $receive_mode = true; + socket_write($msgsock, chr(0)); + $this->read_command($msgsock, $receive_mode); + } else { + socket_write($msgsock, chr(0)); + $control_file = $this->read_bytes($msgsock, $arguments[0]); + socket_write($msgsock, chr(0)); + $this->read_command($msgsock, $receive_mode, $control_file); + } + break; + case 3: + if (!$receive_mode) { + socket_write($msgsock, chr(0)); + $this->read_command($msgsock, $receive_mode); + } else { + socket_write($msgsock, chr(0)); + $data = $this->read_bytes($msgsock, $arguments[0]); + socket_write($msgsock, chr(0)); + socket_close($msgsock); + $this->process_data($data, $control_file); + } + break; + default: + socket_write($msgsock, chr(0)); + break; + } + } + + /** + * @param $data + * @param $control_file + */ + protected function process_data($data, $control_file) + { + $data = preg_split('(\n)', $data); + $dump = []; + foreach ($data as $row) { + $res = []; + $row = preg_split('(\r)', $row); + foreach ($row as $r) { + for ($i = 0, $j = strlen($r); $i < $j; $i++) { + if (!isset($res[$i]) || $r[$i] !== ' ') { + $res[$i] = $r[$i]; + } + } + } + $dump[] = implode('', $res); + } + $dump = implode("\r\n", $dump); + $data = $dump; + + if ($this->handler && is_callable($this->handler)) { + call_user_func($this->handler, $data, $control_file); + } + } +} \ No newline at end of file