?iť?
Current Path : /home/scgforma/www/soc064/htdocs/includes/mike42/escpos-php/src/ |
Current File : /home/scgforma/www/soc064/htdocs/includes/mike42/escpos-php/src/WindowsPrintConnector.php |
<?php /** * escpos-php, a Thermal receipt printer library, for use with * ESC/POS compatible printers. * * Copyright (c) 2014-2015 Michael Billington <michael.billington@gmail.com>, * incorporating modifications by: * - Roni Saha <roni.cse@gmail.com> * - Gergely Radics <gerifield@ustream.tv> * - Warren Doyle <w.doyle@fuelled.co> * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * Connector for sending print jobs to * - local ports on windows (COM1, LPT1, etc) * - shared (SMB) printers from any platform (\\server\foo) * For USB printers or other ports, the trick is to share the printer with a generic text driver, then access it locally. */ class WindowsPrintConnector implements PrintConnector { /** * @var array Accumulated lines of output for later use. */ private $buffer; /** * @var string The hostname of the target machine, or null if this is a local connection. */ private $hostname; /** * @var boolean True if a port is being used directly (must be Windows), false if network shares will be used. */ private $isLocal; /** * @var int Platform we're running on, for selecting different commands. See PLATFORM_* constants. */ private $platform; /** * @var string The name of the target printer (eg "Foo Printer") or port ("COM1", "LPT1"). */ private $printerName; /** * @var string Login name for network printer, or null if not using authentication. */ private $userName; /** * @var string Password for network printer, or null if no password is required. */ private $userPassword; /** * @var string Workgroup that the printer is located on */ private $workgroup; /** * @var int represents Linux */ const PLATFORM_LINUX = 0; /** * @var int represents Mac */ const PLATFORM_MAC = 1; /** * @var int represents Windows */ const PLATFORM_WIN = 2; /** * @var string Valid local ports. */ const REGEX_LOCAL = "/^(LPT\d|COM\d)$/"; /** * @var string Valid printer name. */ const REGEX_PRINTERNAME = "/^[\w-]+(\s[\w-]+)*$/"; /** * @var string Valid smb:// URI containing hostname & printer with optional user & optional password only. */ const REGEX_SMB = "/^smb:\/\/([\s\w-]+(:[\s\w-]+)?@)?[\w-]+\/([\w-]+\/)?[\w-]+(\s[\w-]+)*$/"; /** * @param string $dest * @throws BadMethodCallException */ public function __construct($dest) { $this -> platform = $this -> getCurrentPlatform(); $this -> isLocal = false; $this -> buffer = null; $this -> userName = null; $this -> userPassword = null; $this -> workgroup = null; if(preg_match(self::REGEX_LOCAL, $dest) == 1) { // Straight to LPT1, COM1 or other local port. Allowed only if we are actually on windows. if($this -> platform !== self::PLATFORM_WIN) { throw new BadMethodCallException("WindowsPrintConnector can only be used to print to a local printer ('".$dest."') on a Windows computer."); } $this -> isLocal = true; $this -> hostname = null; $this -> printerName = $dest; } else if(preg_match(self::REGEX_SMB, $dest) == 1) { // Connect to samba share, eg smb://host/printer $part = parse_url($dest); $this -> hostname = $part['host']; /* Printer name and optional workgroup */ $path = ltrim($part['path'], '/'); if(strpos($path, "/") !== false) { $pathPart = explode("/", $path); $this -> workgroup = $pathPart[0]; $this -> printerName = $pathPart[1]; } else { $this -> printerName = $path; } /* Username and password if set */ if(isset($part['user'])) { $this -> userName = $part['user']; if(isset($part['pass'])) { $this -> userPassword = $part['pass']; } } } else if(preg_match(self::REGEX_PRINTERNAME, $dest) == 1) { // Just got a printer name. Assume it's on the current computer. $hostname = gethostname(); if(!$hostname) { $hostname = "localhost"; } $this -> hostname = $hostname; $this -> printerName = $dest; } else { throw new BadMethodCallException("Printer '" . $dest . "' is not a valid printer name. Use local port (LPT1, COM1, etc) or smb://computer/printer notation."); } $this -> buffer = array(); } public function __destruct() { if($this -> buffer !== null) { trigger_error("Print connector was not finalized. Did you forget to close the printer?", E_USER_NOTICE); } } public function finalize() { $data = implode($this -> buffer); $this -> buffer = null; if($this -> platform == self::PLATFORM_WIN) { $this -> finalizeWin($data); } else if($this -> platform == self::PLATFORM_LINUX) { $this -> finalizeLinux($data); } else { $this -> finalizeMac($data); } } /** * Send job to printer -- platform-specific Linux code. * * @param string $data Print data * @throws Exception */ protected function finalizeLinux($data) { /* Non-Windows samba printing */ $device = "//" . $this -> hostname . "/" . $this -> printerName; if($this -> userName !== null) { $user = ($this -> workgroup != null ? ($this -> workgroup . "\\") : "") . $this -> userName; if($this -> userPassword == null) { // No password $command = sprintf("smbclient %s -U %s -c %s -N", escapeshellarg($device), escapeshellarg($user), escapeshellarg("print -")); $redactedCommand = $command; } else { // With password $command = sprintf("smbclient %s %s -U %s -c %s", escapeshellarg($device), escapeshellarg($this -> userPassword), escapeshellarg($user), escapeshellarg("print -")); $redactedCommand = sprintf("smbclient %s %s -U %s -c %s", escapeshellarg($device), escapeshellarg("*****"), escapeshellarg($user), escapeshellarg("print -")); } } else { // No authentication information at all $command = sprintf("smbclient %s -c %s -N", escapeshellarg($device), escapeshellarg("print -")); $redactedCommand = $command; } $retval = $this -> runCommand($command, $outputStr, $errorStr, $data); if($retval != 0) { throw new Exception("Failed to print. Command \"$redactedCommand\" failed with exit code $retval: " . trim($outputStr)); } } protected function finalizeMac($data) { throw new Exception("Mac printing not implemented."); } /** * Send data to printer -- platform-specific Windows code. * * @param string $data */ protected function finalizeWin($data) { /* Windows-friendly printing of all sorts */ if(!$this -> isLocal) { /* Networked printing */ $device = "\\\\" . $this -> hostname . "\\" . $this -> printerName; if($this -> userName !== null) { /* Log in */ $user = "/user:" . ($this -> workgroup != null ? ($this -> workgroup . "\\") : "") . $this -> userName; if($this -> userPassword == null) { $command = sprintf("net use %s %s", escapeshellarg($device), escapeshellarg($user)); $redactedCommand = $command; } else { $command = sprintf("net use %s %s %s", escapeshellarg($device), escapeshellarg($user), escapeshellarg($this -> userPassword)); $redactedCommand = sprintf("net use %s %s %s", escapeshellarg($device), escapeshellarg($user), escapeshellarg("*****")); } $retval = $this -> runCommand($command, $outputStr, $errorStr); if($retval != 0) { throw new Exception("Failed to print. Command \"$redactedCommand\" failed with exit code $retval: " . trim($errorStr)); } } /* Final print-out */ $filename = tempnam(sys_get_temp_dir(), "escpos"); file_put_contents($filename, $data); if(!$this -> runCopy($filename, $device)){ throw new Exception("Failed to copy file to printer"); } unlink($filename); } else { /* Drop data straight on the printer */ if(!$this -> runWrite($data, $this -> printerName)) { throw new Exception("Failed to write file to printer at " . $this -> printerName); } } } /** * @return string Current platform. Separated out for testing purposes. */ protected function getCurrentPlatform() { if(PHP_OS == "WINNT") { return self::PLATFORM_WIN; } if(PHP_OS == "Darwin") { return self::PLATFORM_MAC; } return self::PLATFORM_LINUX; } /* (non-PHPdoc) * @see PrintConnector::read() */ public function read($len) { /* Two-way communication is not supported */ return false; } /** * Run a command, pass it data, and retrieve its return value, standard output, and standard error. * * @param string $command the command to run. * @param string $outputStr variable to fill with standard output. * @param string $errorStr variable to fill with standard error. * @param string $inputStr text to pass to the command's standard input (optional). * @return number */ protected function runCommand($command, &$outputStr, &$errorStr, $inputStr = null) { $descriptors = array( 0 => array("pipe", "r"), 1 => array("pipe", "w"), 2 => array("pipe", "w"), ); $process = proc_open($command, $descriptors, $fd); if (is_resource($process)) { /* Write to input */ if($inputStr !== null) { fwrite($fd[0], $inputStr); } fclose($fd[0]); /* Read stdout */ $outputStr = stream_get_contents($fd[1]); fclose($fd[1]); /* Read stderr */ $errorStr = stream_get_contents($fd[2]); fclose($fd[2]); /* Finish up */ $retval = proc_close($process); return $retval; } else { /* Method calling this should notice a non-zero exit and print an error */ return -1; } } /** * Copy a file. Separated out so that nothing is actually printed during test runs. * * @param string $from Source file * @param string $to Destination file * @return boolean True if copy was successful, false otherwise */ protected function runCopy($from, $to) { return copy($from, $to); } /** * Write data to a file. Separated out so that nothing is actually printed during test runs. * * @param string $data Data to print * @param string $to Destination file * @return boolean True if write was successful, false otherwise */ protected function runWrite($data, $to) { return file_put_contents($data, $to) !== false; } public function write($data) { $this -> buffer[] = $data; } }