false, 'error' => 'Printer IP is not configured.']; } // Determine if IP is local/private. If so, use a very short timeout // because cloud servers cannot reach local IPs anyway. $isLocalIp = preg_match('/^(127\.|10\.|192\.168\.|172\.(1[6-9]|2[0-9]|3[0-1])\.)/', $ip); $timeout = $isLocalIp ? 1 : 5; // 1 second for local, 5 for public try { $fp = @fsockopen($ip, $port, $errno, $errstr, $timeout); if (!$fp) { return ['success' => false, 'error' => "Could not connect to printer at $ip:$port. Error: $errstr ($errno)"]; } fwrite($fp, $data); fclose($fp); return ['success' => true]; } catch (Exception $e) { return ['success' => false, 'error' => 'Exception: ' . $e->getMessage()]; } } /** * Generate basic ESC/POS receipt content. * This is a simplified version. For full features, an ESC/POS library is recommended. */ public static function formatReceipt($order, $items, $company) { $esc = "\x1b"; $gs = "\x1d"; $line = str_repeat("-", 32) . "\n"; $out = ""; $out .= $esc . "!" . "\x38"; // Double height and width $out .= $esc . "a" . "\x01"; // Center align $out .= $company['company_name'] . "\n"; $out .= $esc . "!" . "\x00"; // Reset $out .= $company['address'] . "\n"; $out .= $company['phone'] . "\n\n"; $out .= $esc . "a" . "\x00"; // Left align $out .= "Order ID: #" . $order['id'] . "\n"; $out .= "Date: " . $order['created_at'] . "\n"; $out .= $line; foreach ($items as $item) { $name = substr($item['name'], 0, 20); $qty = $item['quantity'] . "x"; $price = number_format($item['price'], 2); $out .= sprintf("% -20s %3s %7s\n", $name, $qty, $price); } $out .= $line; $out .= sprintf("% -20s %11s\n", "TOTAL", number_format($order['total_amount'], 2)); $out .= "\n\n\n\n"; $out .= $esc . "m"; // Cut paper (optional, depending on printer) return $out; } }