2012-09-06 22 views
1

我试图建立一些PHP代码,通过telnet发送短信到SIM卡服务器,但我在发送连接消息时遇到了麻烦。如何建立连接的短信pdu?获取垃圾邮件

我读过一些关于使用填充位来使编码的消息字节变成八位字节的事情,但我不完全理解它是如何工作的。

我有一个班,接收电话号码,消息(已经拆分为153chars最大),短信总数和当前部分文本的订单号。

只要我在$ hexmessage之前添加了'20',它就会工作。但是在第一部分的开头(在我的消息的第一个字母之前)我得到一个垃圾字符,并且替换第二部分的第一个字母的同一个垃圾字符! (使用'20',所以它会显示一个空格,但它显示一个三角形)

我不明白为什么,或者我不得不改变它以正常工作。

我希望有人能帮助我理解我做错了什么。

这里是我到目前为止有:

<?php 

// Generate PDU string 
public function generatePDUm($receiverNumber,$message, $sms_count, $msg_nr) { 

    //Append filler digit if number is national 
    if(strlen($receiverNumber)==9){ 
     $nacional=1; 
     $receiverNumber = $receiverNumber."F";        
     $network = substr($receiverNumber, 0, 2);      //NETWORK code, used to decide the SIM Card to be used 

    //Check for international flags and set the number type accordingly 
    }else{ 
     $nacional=0; 
     if(substr($receiverNumber, 0, 1)=='+'){ 
      $network = substr($receiverNumber, 4, 2);     //NETWORK code, used to decide the SIM Card to be used 
      $receiverNumber = substr($receiverNumber, 1, 12);   //remove international indicator  
     } 
     else if(substr($receiverNumber, 0, 2)== '00'){ 
      $network = substr($receiverNumber, 5, 2);     //NETWORK code, used to decide the SIM Card to be used 
      $receiverNumber = substr($receiverNumber, 2, 12);   //remove international indicator 
     } 

    } 

    /* Flag the network to be used */ 
    switch ($network){ 
     case "92": 
      $network="TMN"; 
      break; 

     case "96": 
      $network="TMN"; 
      break; 

     case "91": 
      $network="VODAFONE"; 
      break; 

     case "93": 
      $network="OPTIMUS"; 
      break; 
    } 
    // Receiver number must be 10 characters long ('national nr' + filler digit) or less than 13 ('351'+'national nr'). (Portugal) 
    if(strlen($receiverNumber) < 10 || strlen($receiverNumber) > 12) { 
     // Error, not 10 or over 12 numbers long (Code 1) 
     $this->setErrorCode(1); 
     return false; 
    } 

    // Message must be 2 characters long at least 
    if(strlen($message) < 2) { 
     // Error, message too short (Code 2) 
     $this->setErrorCode(2); 
     return false; 
    } 

    // Message can't be longer than 153 characters. 3SMS. 
    if(strlen($message) > 153) { 
     // Error, message too long (Code 3) 
     $this->setErrorCode(3); 
     return false; 
    } 

    // Length of servicecenter number (00 = automatically fixed by phone) 
    $serviceCenterNumberLength = '00'; 

    // SMS-? : 04=sms-deliver(recieve), 11=sms-submit, 01 = dont know but it works, 41 = SMS-SUBMIT + UDH bit (for extended/concatenated SMS) 
    // You can try to change this if your phone does not work with 01 command try to use 11 command 
    $smsType = '41'; 

    // TP Message Reference: (placeholder), let the phone set the message reference number itself 
    $messageRef = '00'; 

    // Number length. If national -> 9, if international -> 12 
    if($nacional==1){ 
     $numberLength = '09'; 
    }else{ 
     $numberLength = '0C'; 
    } 


    // Type of phone adress: (81=Unknown=10dec, 91=InternationalFormat, 92=National?) 
    if($nacional==1){ 
     $numberType = '81'; 
    }else{ 
     $numberType = '91'; 
    } 

    // Get the PDU version of the number 
    $number = $this->getNumberAsPDU($receiverNumber); 

    // TP-PID (Protocol Identifier) 
    $protocolId = '00'; 

    // TP-DCS (Data coding scheme) 
    $dataCodingScheme = '00'; 

    // TP-Validity-Period (timestamp), AA=4days expiry, disabled for SonyEricsson support. 
    // $validityPeriod = 'A0'; 
    // $validityPeriod = 'AA'; // Add this if the PDU command fails 

    /*user data header information (05 - User Data header info length 
    *        00 - Information element identifier for a concatenated short message 
    *        03 - Information element data length 
    *        00 - Reference number, auto 
    *        0.$sms_count - total SMS nr 
    *        0.$msg_nr - current SMS order */ 
    $udhi = '050003000'.$sms_count.'0'.$msg_nr; 
    // echo 'UDHinfo: '.$udhi."\n"; 

    // Data length of message (in hex format) 
    $dataLength = $this->strToHexLen($message); 
    // echo 'DATA LENGHT: '.$dataLength."\n\n"; 

    // Convert message, string > 7bits > 8bits > hex 
    $hexMessage = $this->bit7tohex($this->strto7bit($message)); 


    // Create the complete PDU string 
    $pdu = $serviceCenterNumberLength . $smsType . $messageRef . $numberLength . 
      $numberType . $number . $protocolId . $dataCodingScheme . $dataLength . 
      $udhi . '20' .$hexMessage; 

    /* 
    * Generate the length of var $pdu (pdu/2 minus 1) as pdu format requests 
    * The -1 is because we don't count the first two characters '00', needed for this command: 'cmgs=24' 
    */ 
    $cmgslen = strlen($pdu)/2-1; 

    // Build data array to return with required information 
    $data = array(); 
    $data['pdu'] = $pdu; 
    $data['cmgslen'] = $cmgslen; 
    $data['rede'] = $network; 

    // Return the data array with PDU information 
    return $data; 
} 


// Generate PDU formatted cellphone number 
private function getNumberAsPDU($number) { 

     // Length of number divided by 2 handle two characters each time 
    $length = strlen($number)/2; 
    // Set counter to 1 for strlen 
    $i = 1; 
    $pduNumber = ''; 

    // Loop to handle every 2 characters of the phone number. 06 12 34 56 78 
    while ($i <= $length) { 
     // Get 2 characters of the complete string depending on the number of the current loop. 
     // Then reverse these 2 characters and put them in var $pduNumber (06 = 60) 
     $pduNumber .= strrev(substr($number,$i*2-2,2)); 
     // Counter + 1 
     $i++; 
    } 

    // Return the generated number 
    return $pduNumber; 
} 


/* Function to convert ascii character to 8 bits 
* Much more efficient than holding a complete ASCII table 
* Thanks to Mattijs F. 
*/ 
private function asc2bin($input, $length=8) { 

    $bin_out = ''; 
    // Loop through every character in the string 
    for($charCount=0; $charCount < strlen($input); $charCount++) { 
     $charAscii = ord($input{$charCount}); // ascii value of character 
     $charBinary = decbin($charAscii); // decimal to binary 
     $charBinary = str_pad($charBinary, $length, '0', STR_PAD_LEFT); 
     $bin_out .= $charBinary; 
    } 

    // Return complete generated string 
    return $bin_out; 
} 


// String to 7 bits array 
private function strto7bit($message) { 
    $message = trim($message); 
    $length = strlen($message); 
    $i = 1; 
    $bitArray = array(); 

    // Loop through every character in the string 
    while ($i <= $length) { 
     // Convert this character to a 7 bits value and insert it into the array 
     $bitArray[] = $this->asc2bin(substr($message ,$i-1,1) ,7); 
     $i++; 
    } 


    // Return array containing 7 bits values 
    return $bitArray; 
} 


// Convert 8 bits binary string to hex values (like F2) 
private function bit8tohex($bin, $padding=false, $uppercase=true) { 
    $hex = ''; 
    // Last item for counter (for-loop) 
    $last = strlen($bin)-1; 
    // Loop for every item 
    for($i=0; $i<=$last; $i++) { 
     $hex += $bin[$last-$i] * pow(2,$i); 
    } 

    // Convert from decimal to hexadecimal 
    $hex = dechex($hex); 
    // Add a 0 (zero) if there is only 1 value returned, like 'F' 
    if($padding && strlen($hex) < 2) { 
     $hex = '0'.$hex; 
    } 

    // If we want the output returned as UPPERCASE do this 
    if($uppercase) { 
     $hex = strtoupper($hex); 
    } 

    // Return the hexadecimal value 
    return $hex; 
} 


// Convert 7 bits binary to hex, 7 bits > 8 bits > hex 
private function bit7tohex($bits) { 

    $i = 0; 
    $hexOutput = ''; 
    $running = true; 

    // For every 7 bits character array item 
    while($running) { 

     if(count($bits)==$i+1) { 
      $running = false; 
     } 

     $value = $bits[$i]; 

     if($value=='') { 
      $i++; 
      continue; 
     } 

     // Convert the 7 bits value to the 8 bits value 
     // Merge a part of the next array element and a part of the current one 

     // Default: new value is current value 
     $new = $value; 

     if(key_exists(($i+1), $bits)) { 
      // There is a next array item so make it 8 bits 
      $neededChar = 8 - strlen($value); 
      // Get the char;s from the next array item 
      $charFromNext = substr($bits[$i+1], -$neededChar); 
      // Remove used bit's from next array item 
      $bits[$i+1] = substr($bits[$i+1], 0, strlen($bits[$i+1])-$neededChar); 
      // New value is characters from next value and current value 
      $new = $charFromNext.$value; 
     } 

     if($new!='') { 
      // Always make 8 bits 
      $new = str_pad($new, 8, '0', STR_PAD_LEFT); 
      // The 8 bits to hex conversion 
      $hexOutput .= $this->bit8tohex($new, true); 
     } 

     $i++; 
    } 

    // Return the 7bits->8bits->hexadecimal generated value 
    return $hexOutput; 
} 

// String to length in Hex, String > StringLength > Hex 
private function strToHexLen($message) { 

    // Length of the string (message) 
    $length = strlen($message)+7; //+7 for UDH. the UDH is a total of (number of octets x bit size of octets) 6 x 8 = 48 bits long. Therefore a single bit of padding has to be prepended to the message. The UDH is therefore (bits for UDH/bits per septet) = (48 + 1)/7 = 7 septets in length. 
    // Hex value of this string length 
    $hex = dechex($length); 

    // Length of the hex value 
    $hexLength = strlen($hex); 
    // If the hex strng length is lower dan 2 
    if($hexLength < 2) { 
     // Add a 0 (zero) before it 
     $hex = '0'.$hex; 
    } 

    // Return the hex value in UPPERCASE characters 
    return strtoupper($hex); 
} 

} 
?> 

回答

2

正如你已经知道,创建级联短信,需要您的短信,然后添加一个UDH。 UDH成为您的有效载荷的一部分,从而减少了您可以发送的每个段的字符数。

由于它已成为您的有效载荷的一部分,它需要确认您的有效载荷数据要求 - 这是7位。然而,UDH是8位,这显然使事情复杂化。

考虑以下的UDH:

050003000302 
  • 05是的UDH
  • 00的长度为IEI
  • 03是IEDL(3更多个八位字节)
  • 00是一个参考(这个数字在你的每个级联消息UDH中必须相同)
  • 03是消息的最大数量
  • 02是当前消息编号。

这是总共6个八位字节 - 相当于48位。这一切都很好,但由于UDH实际上是SMS消息的一部分,因此您需要做的是添加更多位,以便实际消息从七个边界开始。一个七位边界是每7位,所以在这种情况下,我们将不得不再增加1位数据来使UDH为49位,然后我们可以添加标准的GSM-7编码字符。

您可以从Here

0

阅读了更多有关这这些问题是所有的地方和似乎没有人能够回答他们的方式,使任何意义。零填充通常会让事情变得更糟。我认为在GMS标准中解决这个设计缺陷的最简单方法是使用8位编码或16位UCS2,即使这意味着更少的字符。这样你就不需要关心字节边界的差异,这就是创建串联的SMS非常困难的原因。