¡£¤¥§¿ÄÅÆÇÉÑÖØÜßàèéùìòå¿äöñüà\nGreek: ΩΘΔΦΓΛΩΠΨΣΘΞ";
/*
* A Unicode SMS can contain only 70 characters. Any Unicode character can be sent,
* including those GSM and accented ISO-8859 European characters that are not
* catered for by the GSM character set, but note that mobile phones are only able
* to display certain Unicode characters, based on their geographic market.
* Nonetheless, every mobile phone should be able to display at least the text
* "Unicode test message:" from the test message below. Your browser may be able to
* display more of the characters than your phone. The text of the message below is:
*/
$unicode_msg = "Unicode test message: ☺ \nArabic: شصض\nChinese: 本网";
/*
* There are a number of 8 bit messages that one can send to a handset, the most popular of the lot is Service Indication(Wap Push).
* Some other popular ones are vCards and vCalendars, headers may vary depending on which of message one opts to send.
* The User Data Header(UDH) is solely responsible for determining which
* type of messages will be sent to one's handset.
* In a nutshell, SI(service indication) messages will have, in the final message body, both the UDH
* and WSP(Wireless Session Protocol) appended to each other forming a prefix of the ASCII string of the Hex value
* of the actual content. For example, suppose our intended Wap message body is as follows:
*
* Visit BulkSMS.com homepage
*
* Our headers will be -- UDH + WSP = FINAL_HEADER
* '0605040B8423F0' + 'DC0601AE' = '0605040B8423F0DC0601AE'
*
* The UDH contains a destination port(0B84) and the origin port(23F0)
* the WSP is broken down into the following:
*
* DC - Transaction ID (used to associate PDUs)
* 06 - PDU type (push PDU)
* 01 - HeadersLen (total of content-type and headers, i.e. zero headers)
* AE - Content Type: application/vnd.wap.sic
*
* For this example our 8 bit message(what becomes our Wap Push) will look like this:
* $msg = '0605040B8423F0DC0601AE02056a0045c60d0362756c6b736d732e636f6d00010356697369742042756c6b534d532e636f6d20686f6d6570616765000101';
*
* You will only get UDH for both vCard and vCalendar type of 8 bit messages and no WSP, which will look something to this effect:
* '06050423F4000'
*
* In order to convert an xml document into its binary representation (wbxml), one would need to install a wbxml library (libwbxml)
* Once that has been successfully achieved, that binary representation will then be finally converted into its hexadecimal value
* in order to complete the transaction. With that done, the appropriate headers are then appended to this hex string to complete
* the Wap Push/8-bit messaging
*
* $eight_bit_msg = get_headers( $msg_type ) . xml_to_wbxml( $msg_body );
* get_headers(...) function commented out. uncomment when you use it.
* $msg_type = 'wap_push';
* $msg_body = 'Visit BulkSMS.com homepage';
*/
$eight_bit_msg = '0605040B8423F0DC0601AE02056a0045c60d0362756c6b736d732e636f6d00010356697369742042756c6b534d532e636f6d20686f6d6570616765000101';
/*
* These error codes will be retried if encountered. For your final application,
* you may wish to include statuses such as "25: You do not have sufficient credits"
* in this list, and notify yourself upon such errors. However, if you are writing a
* simple application which does no queueing (e.g. a Web page where a user simply
* POSTs a form back to the page that will send the message), then you should not
* add anything to this list (perhaps even removing the item below), and rather just
* display an error to your user immediately.
*/
$transient_errors = array(
40 => 1 # Temporarily unavailable
);
/*
* Sending 7-bit message
*/
$post_body = seven_bit_sms( $username, $password, $seven_bit_msg, $msisdn );
$result = send_message( $post_body, $url, $port );
if( $result['success'] ) {
print_ln( formatted_server_response( $result ) );
}
else {
print_ln( formatted_server_response( $result ) );
}
/*
* Sending unicode message
*/
$post_body = unicode_sms( $username, $password, $unicode_msg, $msisdn );
$result = send_message( $post_body, $url, $port );
if( $result['success'] ) {
print_ln( formatted_server_response( $result ) );
}
else {
print_ln( formatted_server_response( $result ) );
}
/*
* Sending 8-bit message
*/
$post_body = eight_bit_sms( $username, $password, $eight_bit_msg, $msisdn );
$result = send_message( $post_body, $url, $port );
if( $result['success'] ) {
print_ln( formatted_server_response( $result ) );
}
else {
print_ln( formatted_server_response( $result ) );
}
/*
* If you don't see this, and no errors appeared to screen, you should
* check your Web server's error logs for error output:
*/
print_ln("Script ran to completion");
function print_ln($content) {
if (isset($_SERVER["SERVER_NAME"])) {
print $content."
";
}
else {
print $content."\n";
}
}
function formatted_server_response( $result ) {
$this_result = "";
if ($result['success']) {
$this_result .= "Success: batch ID " .$result['api_batch_id']. "API message: ".$result['api_message']. "\nFull details " .$result['details'];
}
else {
$this_result .= "Fatal error: HTTP status " .$result['http_status_code']. ", API status " .$result['api_status_code']. " API message " .$result['api_message']. " full details " .$result['details'];
if ($result['transient_error']) {
$this_result .= "This is a transient error - you should retry it in a production environment";
}
}
return $this_result;
}
function send_message ( $post_body, $url, $port ) {
/*
* Do not supply $post_fields directly as an argument to CURLOPT_POSTFIELDS,
* despite what the PHP documentation suggests: cUrl will turn it into in a
* multipart formpost, which is not supported:
*/
$ch = curl_init( );
curl_setopt ( $ch, CURLOPT_URL, $url );
curl_setopt ( $ch, CURLOPT_PORT, $port );
curl_setopt ( $ch, CURLOPT_POST, 1 );
curl_setopt ( $ch, CURLOPT_RETURNTRANSFER, 1 );
curl_setopt ( $ch, CURLOPT_POSTFIELDS, $post_body );
// Allowing cUrl funtions 20 second to execute
curl_setopt ( $ch, CURLOPT_TIMEOUT, 20 );
// Waiting 20 seconds while trying to connect
curl_setopt ( $ch, CURLOPT_CONNECTTIMEOUT, 20 );
$response_string = curl_exec( $ch );
$curl_info = curl_getinfo( $ch );
$sms_result = array();
$sms_result['success'] = 0;
$sms_result['details'] = '';
$sms_result['transient_error'] = 0;
$sms_result['http_status_code'] = $curl_info['http_code'];
$sms_result['api_status_code'] = '';
$sms_result['api_message'] = '';
$sms_result['api_batch_id'] = '';
if ( $response_string == FALSE ) {
$sms_result['details'] .= "cURL error: " . curl_error( $ch ) . "\n";
} elseif ( $curl_info[ 'http_code' ] != 200 ) {
$sms_result['transient_error'] = 1;
$sms_result['details'] .= "Error: non-200 HTTP status code: " . $curl_info[ 'http_code' ] . "\n";
}
else {
$sms_result['details'] .= "Response from server: $response_string\n";
$api_result = explode( '|', $response_string );
$status_code = $api_result[0];
$sms_result['api_status_code'] = $status_code;
$sms_result['api_message'] = $api_result[1];
if ( count( $api_result ) != 3 ) {
$sms_result['details'] .= "Error: could not parse valid return data from server.\n" . count( $api_result );
} else {
if ($status_code == '0') {
$sms_result['success'] = 1;
$sms_result['api_batch_id'] = $api_result[2];
$sms_result['details'] .= "Message sent - batch ID $api_result[2]\n";
}
else if ($status_code == '1') {
# Success: scheduled for later sending.
$sms_result['success'] = 1;
$sms_result['api_batch_id'] = $api_result[2];
}
else {
$sms_result['details'] .= "Error sending: status code [$api_result[0]] description [$api_result[1]]\n";
}
}
}
curl_close( $ch );
return $sms_result;
}
function seven_bit_sms ( $username, $password, $message, $msisdn ) {
$post_fields = array (
'username' => $username,
'password' => $password,
'message' => character_resolve( $message ),
'msisdn' => $msisdn
);
return make_post_body($post_fields);
}
function unicode_sms ( $username, $password, $message, $msisdn ) {
$post_fields = array (
'username' => $username,
'password' => $password,
'message' => string_to_utf16_hex( $message ),
'msisdn' => $msisdn,
'dca' => '16bit'
);
return make_post_body($post_fields);
}
/*
function get_headers ( $msg_type ) {
if( $msg_type == 'wap_push' ) {
$udh = '0605040B8423F0';
$wsp = 'DC0601AE';
return $udh . $wsp;
}
else if( $msg_type == 'vCard' || $msg_type == 'vCalendar' ) {
return '06050423F40000';
}
}
*/
function eight_bit_sms( $username, $password, $message, $msisdn ) {
$post_fields = array (
'username' => $username,
'password' => $password,
'message' => $message,
'msisdn' => $msisdn,
'dca' => '8bit'
);
return make_post_body($post_fields);
}
function make_post_body($post_fields) {
$stop_dup_id = make_stop_dup_id();
if ($stop_dup_id > 0) {
$post_fields['stop_dup_id'] = make_stop_dup_id();
}
$post_body = '';
foreach( $post_fields as $key => $value ) {
$post_body .= urlencode( $key ).'='.urlencode( $value ).'&';
}
$post_body = rtrim( $post_body,'&' );
return $post_body;
}
function character_resolve($body) {
$special_chrs = array(
'Δ'=>'0xD0', 'Φ'=>'0xDE', 'Γ'=>'0xAC', 'Λ'=>'0xC2', 'Ω'=>'0xDB',
'Π'=>'0xBA', 'Ψ'=>'0xDD', 'Σ'=>'0xCA', 'Θ'=>'0xD4', 'Ξ'=>'0xB1',
'¡'=>'0xA1', '£'=>'0xA3', '¤'=>'0xA4', '¥'=>'0xA5', '§'=>'0xA7',
'¿'=>'0xBF', 'Ä'=>'0xC4', 'Å'=>'0xC5', 'Æ'=>'0xC6', 'Ç'=>'0xC7',
'É'=>'0xC9', 'Ñ'=>'0xD1', 'Ö'=>'0xD6', 'Ø'=>'0xD8', 'Ü'=>'0xDC',
'ß'=>'0xDF', 'à'=>'0xE0', 'ä'=>'0xE4', 'å'=>'0xE5', 'æ'=>'0xE6',
'è'=>'0xE8', 'é'=>'0xE9', 'ì'=>'0xEC', 'ñ'=>'0xF1', 'ò'=>'0xF2',
'ö'=>'0xF6', 'ø'=>'0xF8', 'ù'=>'0xF9', 'ü'=>'0xFC',
);
$ret_msg = '';
if( mb_detect_encoding($body, 'UTF-8') != 'UTF-8' ) {
$body = utf8_encode($body);
}
for ( $i = 0; $i < mb_strlen( $body, 'UTF-8' ); $i++ ) {
$c = mb_substr( $body, $i, 1, 'UTF-8' );
if( isset( $special_chrs[ $c ] ) ) {
$ret_msg .= chr( $special_chrs[ $c ] );
}
else {
$ret_msg .= $c;
}
}
return $ret_msg;
}
/*
* Unique ID to eliminate duplicates in case of network timeouts - see
* EAPI documentation for more. You may want to use a database primary
* key. Warning: sending two different messages with the same
* ID will result in the second being ignored!
*
* Don't use a timestamp - for instance, your application may be able
* to generate multiple messages with the same ID within a second, or
* part thereof.
*
* You can't simply use an incrementing counter, if there's a chance that
* the counter will be reset.
*/
function make_stop_dup_id() {
return 0;
}
function string_to_utf16_hex( $string ) {
return bin2hex(mb_convert_encoding($string, "UTF-16", "UTF-8"));
}
function xml_to_wbxml( $msg_body ) {
$wbxmlfile = 'xml2wbxml_'.md5(uniqid(time())).'.wbxml';
$xmlfile = 'xml2wbxml_'.md5(uniqid(time())).'.xml';
//create temp file
$fp = fopen($xmlfile, 'w+');
fwrite($fp, $msg_body);
fclose($fp);
//convert temp file
exec(xml2wbxml.' -v 1.2 -o '.$wbxmlfile.' '.$xmlfile.' 2>/dev/null');
if(!file_exists($wbxmlfile)) {
print_ln('Fatal error: xml2wbxml conversion failed');
return false;
}
$wbxml = trim(file_get_contents($wbxmlfile));
//remove temp files
unlink($xmlfile);
unlink($wbxmlfile);
return $wbxml;
}
?>