Send Push Notifications to Windows Phone 7 from PHP

November 15, 2010 by
 

I couldn’t find a library for sending Push Notifications to Windows Phone 7 from PHP.  Most samples were using an ASP.NET web service.  For those of us who would like to run Push Notifications from cheaper PHP and cURL enabled hosting, I’ve created a little helper class: (The XML may be break below, so here is the Text Version)

class WindowsPhonePushPriority
{
    const TileImmediately = 1;
    const ToastImmediately = 2;
    const RawImmediately = 3;
    const TileWait450 = 11;
    const ToastWait450 = 12;
    const RawWait450 = 13;
    const TileWait900 = 21;	
    const ToastWait900 = 22;	
    const RawWait900 = 23;
}
 
class WindowsPhonePushClient
{
    private $device_url = '';
    private $debug_mode = false;
 
    function __construct($device_url)
    {
        $this->device_url = $device_url;
    }
 
    public function send_raw_update($msg, $priority = WindowsPhonePushPriority::RawImmediately)
    {
        return $this->_send_push(array('X-NotificationClass: ' . $priority), $msg);
    }
 
    public function send_tile_update($image_url, $count, $title, $priority = WindowsPhonePushPriority::TileImmediately)
    {
        $msg = "< ?xml version=\"1.0\" encoding=\"utf-8\"?>" .
                "<wp :Notification xmlns:wp=\"WPNotification\">" .
                   "</wp><wp :Tile>".
                      "</wp><wp :BackgroundImage>" . $image_url . "</wp>" .
                      "<wp :Count>" . $count . "</wp>" .
                      "<wp :Title>" . $title . "</wp>" .
                   " " .
                "";
 
        return $this->_send_push(array(
                                    'X-WindowsPhone-Target: token',
                                    'X-NotificationClass: ' . $priority,
                                ), $msg);
    }
 
    private function send_toast($title, $message, $priority = WindowsPhonePushPriority::ToastImmediately)
    {
        $msg = "< ?xml version=\"1.0\" encoding=\"utf-8\"?>" .
            "<wp :Notification xmlns:wp=\"WPNotification\">" .
                "</wp><wp :Toast>" .
                    "</wp><wp :Text1>" . $title . "</wp>" .
                    "<wp :Text2>" . $message . "</wp>" .
                "" .
            "";
 
        return $this->_send_push($url, array(
                                      'X-WindowsPhone-Target: toast',
                                      'X-NotificationClass: ' . $priority, 
                                      ), $msg);
    }
 
    private function _send_push($headers, $msg)
    {
        $ch = curl_init();
        curl_setopt($ch, CURLOPT_URL, $this->device_url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_POST, true);
        curl_setopt($ch, CURLOPT_HEADER, true); 
        curl_setopt($ch, CURLOPT_HTTPHEADER,    // Add these headers to all requests
            $headers + array(
                            'Content-Type: text/xml',
                            'Accept: application/*'
                            )
            ); 
        curl_setopt($ch, CURLOPT_POSTFIELDS, $msg);
 
        if ($this->debug_mode)
        {
            curl_setopt($ch, CURLOPT_VERBOSE, $this->debug_mode);
            curl_setopt($ch, CURLOPT_STDERR, fopen('debug.log','w'));
        }
        $output = curl_exec($ch);
        curl_close($ch);
 
        return array(
            'X-SubscriptionStatus'     => $this->_get_header_value($output, 'X-SubscriptionStatus'),
            'X-NotificationStatus'     => $this->_get_header_value($output, 'X-NotificationStatus'),
            'X-DeviceConnectionStatus' => $this->_get_header_value($output, 'X-DeviceConnectionStatus')
            );
    }
 
    private function _get_header_value($content, $header)
    {
        return preg_match_all("/$header: (.*)/i", $content, $match) ? $match[1][0] : "";
    }
}

This code supports sending all three types of push notifications, Tile, Toast and Raw.

To use the class, simply include the file and call the constructor with the Device URL, which has already been uploaded to your server from the devices themselves.

Comments

17 Comments on Send Push Notifications to Windows Phone 7 from PHP

  1. olivier on Thu, 25th Nov 2010 11:23 AM
  2. Hy,
    Thank you for your code, I have been looking for a while for a php solution to send push.
    But, I have a problem with your code, I receive the notification but can’t read id.
    I have an exception at : “string notificationText = reader.ReadString();”

    Got raw notification:
    ‘taskhost.exe’ (Managé) : ‘System.SR.dll’ chargé
    Une exception de première chance de type ‘System.IO.EndOfStreamException’ s’est produite dans mscorlib.dll
    System.IO.EndOfStreamException: Unable to read beyond the end of the stream.
    à System.IO.__Error.EndOfFile()
    à System.IO.BinaryReader.ReadString()

    I can’t find where it come from.
    I home you can help me :)

  3. Ram on Tue, 14th Dec 2010 10:46 AM
  4. Thanks — excellent starting point. I had to fix a few minor things to make it work:

    1) send_toast needs to be changed to “public”
    2) the call to the private function _send_push from send_toast needed to have the extra parameter removed
    3) the XML needed to be fixed (I think Microsoft may have changed the specification since this was published) — the specs for the correct XML are at http://msdn.microsoft.com/en-us/library/ff402545%28VS.92%29.aspx

  5. Dave on Tue, 11th Jan 2011 3:36 PM
  6. @Ram -

    I’ve updated the code, but I didn’t need to change the XML. This code is live and working great, can you be more specific about what wasn’t working?

  7. Jeff on Tue, 11th Jan 2011 4:46 PM
  8. Dave, is there any chance you can include code in an example form? So taking your script and actually showing how you call it? I posted your code above and even though I didn’t get any errors, I didn’t get a notification on my phone either…

    Thanks!

  9. Dave on Tue, 11th Jan 2011 4:59 PM
  10. @Jeff –

    Examine the response code from the method that sends the notification.

    $cli = new WindowsPhonePushClient(‘http://sb1.live.net….’);
    var_dump($cli->send_toast(‘title’,'message text’);

    There really isn’t much to it. Make sure you have the right URL for your device.

  11. Jeff on Tue, 11th Jan 2011 5:02 PM
  12. @Dave –

    array(3) { ["X-SubscriptionStatus"]=> string(7) “Expired” ["X-NotificationStatus"]=> string(7) “Dropped” ["X-DeviceConnectionStatus"]=> string(12) “Disconnected” } var_dump

    What does this mean?

  13. Jeff on Tue, 11th Jan 2011 5:06 PM
  14. @Dave –
    I tried again after I changed the following in my app:
    myChannel = HttpNotificationChannel.Find(“OilChangeAppNotify”);

    After putting in the new URI I got this:
    array(3) { ["X-SubscriptionStatus"]=> string(6) “Active” ["X-NotificationStatus"]=> string(10) “Suppressed” ["X-DeviceConnectionStatus"]=> string(9) “Connected” } var_dump

  15. Dave on Tue, 11th Jan 2011 5:08 PM
  16. @Jeff -

    Check out this page for the meaning behind those response codes: http://msdn.microsoft.com/en-us/library/ff941100(VS.92).aspx

    It looks like you have not called BindToShellToast.
    After your Find call, you’ll want something like this:

    if (!_channel.IsShellToastBound) _channel.BindToShellToast();

    I suggest you grab the sample projects from MSDN for push notifications, they have some good code that sets up the channel properly.

  17. Jeff on Tue, 11th Jan 2011 7:05 PM
  18. @Dave – That looks to be the issue. I have successfully received a Toast message in the emulator using your script! That is awesome!

    Thanks!

  19. Jeff on Tue, 11th Jan 2011 8:07 PM
  20. @Dave – Quick question… Is there a way to send a notification to a specific phone? I have the ANID…

    Thanks!

  21. Dave on Tue, 11th Jan 2011 8:10 PM
  22. @Jeff – the only way to send a notification to a phone i via the URL provided when opening a notification channel. I don’t believe it is possible to send a notification by knowing only the ANID.

  23. Jeff on Tue, 11th Jan 2011 9:01 PM
  24. Does the app generate a unique URI for every install?

  25. Dave on Tue, 11th Jan 2011 9:03 PM
  26. Yes, each channel subscription, on each device, has a unique URL.

  27. olivier on Thu, 13th Jan 2011 9:51 AM
  28. Thanks for the update :)
    I’ll try it soon.

  29. billy riantono on Fri, 25th Mar 2011 2:55 AM
  30. Thanks this code work perfectly for me :)

  31. cubed on Thu, 16th Feb 2012 7:44 AM
  32. Super Sache, funktioniert sehr gut! Vielen Dank dafür! Hat mir echt eine Menge Kopfzerbrechen erspart!!

  33. Ken on Mon, 20th Feb 2012 9:35 PM
  34. Have you thought of adding support for https so that you are not limited to the 500 per day? I’ve tried without luck to get php code that can send a certificate to the servers in a manner that they would accept it.