如何在PHP脚本中拨打SIP分机并维持通话60秒?
Great question! Since you’re only needing a basic SIP connection (no audio, internal subnet only) to trigger your IVR, you don’t need heavyweight VoIP libraries or third-party services. Here are two straightforward approaches tailored to your use case:
SIPp is a widely used open-source tool for testing SIP infrastructure, and it’s perfect for your scenario—it can quickly initiate a call, hold it for a set duration, and requires minimal setup.
Step 1: Install SIPp
On Debian/Ubuntu systems:
sudo apt-get install sipp
On RHEL/CentOS:
sudo yum install sipp
Step 2: PHP Script to Trigger the Call
Use PHP’s shell_exec() or exec() to run the SIPp command. This example initiates a single call, holds it for 60 seconds, and skips media transmission:
<?php // Configure your SIP target details $sipTarget = 'sip:5555@192.168.55.5:5060'; $callDuration = 60; // Hold time in seconds // Build the SIPp command: // -m 1: Send 1 call // -d {$callDuration}000: Hold the call for X milliseconds // -sf /dev/null: Use default call flow (no custom script) // -recv_timeout 10000: Wait 10s for responses before timing out $command = "sipp {$sipTarget} -m 1 -d {$callDuration}000 -sf /dev/null -recv_timeout 10000"; // Execute the command and capture output $output = shell_exec($command . ' 2>&1'); // Verify call success if (strpos($output, 'Successful calls: 1') !== false) { echo "IVR trigger call established and held for {$callDuration} seconds."; } else { echo "Call failed. Debug output: " . htmlspecialchars($output); } ?>
This is the most reliable option because SIPp handles all the low-level SIP handshake logic (INVITE → 200 OK → ACK → BYE) automatically.
If you can’t install SIPp, you can build and send raw SIP messages using PHP’s socket functions. This requires manually handling the SIP handshake, but it works without any external dependencies.
PHP Script with Raw SIP Messages
<?php // SIP target configuration $targetIp = '192.168.55.5'; $targetPort = 5060; $callerUri = 'sip:php-trigger@' . gethostbyname(gethostname()); // Your server's SIP URI $calleeUri = 'sip:5555@192.168.55.5:5060'; $holdDuration = 60; // Create UDP socket (SIP typically uses UDP) $socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); if (!$socket) { die("Failed to create socket: " . socket_strerror(socket_last_error())); } socket_set_timeout($socket, 10); // 10s timeout for responses // Generate unique SIP headers $callId = uniqid('php-sip-') . '@' . gethostname(); $branch = 'z9hG4bK-' . uniqid(); // Required for SIP Via header $fromTag = uniqid(); // 1. Send INVITE request to initiate call $invite = "INVITE {$calleeUri} SIP/2.0\r\n"; $invite .= "Via: SIP/2.0/UDP " . gethostbyname(gethostname()) . ":5060;branch={$branch}\r\n"; $invite .= "From: {$callerUri};tag={$fromTag}\r\n"; $invite .= "To: {$calleeUri}\r\n"; $invite .= "Call-ID: {$callId}\r\n"; $invite .= "CSeq: 1 INVITE\r\n"; $invite .= "Contact: {$callerUri}\r\n"; $invite .= "Content-Length: 0\r\n"; $invite .= "Max-Forwards: 70\r\n\r\n"; socket_sendto($socket, $invite, strlen($invite), 0, $targetIp, $targetPort); // 2. Wait for 200 OK response and send ACK $response = ''; $toTag = ''; $callEstablished = false; while ($buf = socket_read($socket, 4096)) { $response .= $buf; if (strpos($response, 'SIP/2.0 200 OK') !== false) { // Extract the To tag from the server's response preg_match('/To: .*?tag=(.*?)\r\n/', $response, $matches); $toTag = $matches[1] ?? ''; if ($toTag) { // Send ACK to confirm call establishment $ack = "ACK {$calleeUri} SIP/2.0\r\n"; $ack .= "Via: SIP/2.0/UDP " . gethostbyname(gethostname()) . ":5060;branch={$branch}\r\n"; $ack .= "From: {$callerUri};tag={$fromTag}\r\n"; $ack .= "To: {$calleeUri};tag={$toTag}\r\n"; $ack .= "Call-ID: {$callId}\r\n"; $ack .= "CSeq: 1 ACK\r\n"; $ack .= "Content-Length: 0\r\n\r\n"; socket_sendto($socket, $ack, strlen($ack), 0, $targetIp, $targetPort); $callEstablished = true; break; } } } if ($callEstablished) { echo "Call established, holding for {$holdDuration} seconds...\n"; sleep($holdDuration); // 3. Send BYE to terminate the call $bye = "BYE {$calleeUri} SIP/2.0\r\n"; $bye .= "Via: SIP/2.0/UDP " . gethostbyname(gethostname()) . ":5060;branch={$branch}\r\n"; $bye .= "From: {$callerUri};tag={$fromTag}\r\n"; $bye .= "To: {$calleeUri};tag={$toTag}\r\n"; $bye .= "Call-ID: {$callId}\r\n"; $bye .= "CSeq: 2 BYE\r\n"; // CSeq increments for each new request $bye .= "Content-Length: 0\r\n\r\n"; socket_sendto($socket, $bye, strlen($bye), 0, $targetIp, $targetPort); // Wait for BYE confirmation socket_read($socket, 4096); echo "Call terminated successfully.\n"; } else { echo "Failed to establish call. Server response: " . htmlspecialchars($response); } socket_close($socket); ?>
Key Notes for This Approach:
- Ensure your server’s firewall allows UDP port 5060 (or TCP if your IVR uses it—switch to
SOCK_STREAMandsocket_connect()in that case). - SIP headers must be formatted correctly (trailing
\r\nare mandatory, and unique Call-ID/Branch values are required for each call). - This is more manual, so test with your IVR first to confirm it accepts the SIP messages.
内容的提问来源于stack exchange,提问作者Nanosynth

