├── src └── Pushbullet │ ├── Exceptions │ ├── PushbulletException.php │ ├── ConnectionException.php │ ├── DeprecatedException.php │ ├── InvalidTokenException.php │ ├── FilePushException.php │ ├── NotFoundException.php │ ├── ChannelException.php │ ├── InvalidRecipientException.php │ ├── NoSmsException.php │ └── NotPushableException.php │ ├── Push.php │ ├── PhonebookEntry.php │ ├── Contact.php │ ├── Device.php │ ├── Connection.php │ ├── Channel.php │ ├── Pushable.php │ └── Pushbullet.php ├── composer.json ├── LICENSE ├── .gitignore └── README.md /src/Pushbullet/Exceptions/PushbulletException.php: -------------------------------------------------------------------------------- 1 | = 5.4.0", 25 | "ext-curl": "*" 26 | }, 27 | "autoload": { 28 | "psr-4": { 29 | "Pushbullet\\": "src/Pushbullet" 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /src/Pushbullet/Push.php: -------------------------------------------------------------------------------- 1 | $v) { 17 | $this->$k = $v ?: null; 18 | } 19 | 20 | $this->apiKey = $apiKey; 21 | } 22 | 23 | /** 24 | * Dismiss the push notification. 25 | * 26 | * @return Push The same push notification, now dismissed. 27 | * @throws Exceptions\ConnectionException 28 | */ 29 | public function dismiss() 30 | { 31 | return new Push(Connection::sendCurlRequest(Connection::URL_PUSHES . '/' . $this->iden, 'POST', 32 | ['dismissed' => true], true, $this->apiKey), $this->apiKey); 33 | } 34 | 35 | /** 36 | * Delete the push notification. 37 | * 38 | * @throws Exceptions\ConnectionException 39 | */ 40 | public function delete() 41 | { 42 | Connection::sendCurlRequest(Connection::URL_PUSHES . '/' . $this->iden, 'DELETE', null, false, $this->apiKey); 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/Pushbullet/PhonebookEntry.php: -------------------------------------------------------------------------------- 1 | $v) { 17 | $this->$k = $v ?: null; 18 | } 19 | 20 | $this->deviceParent = $parent; 21 | } 22 | 23 | /** 24 | * Send an SMS message to the contact. 25 | * 26 | * @param string $message Message. 27 | * 28 | * @return Push 29 | * @throws Exceptions\ConnectionException 30 | * @throws Exceptions\InvalidRecipientException Thrown if the contact doesn't have a number. 31 | * @throws Exceptions\NoSmsException Thrown if the device cannot send SMS messages. 32 | */ 33 | public function sendSms($message) 34 | { 35 | if (empty($this->phone)) { 36 | throw new Exceptions\InvalidRecipientException("Phonebook entry doesn't have a phone number."); 37 | } 38 | 39 | return $this->deviceParent->sendSms($this->phone, $message); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013-2015 Ivaylo Stoyanov - https://github.com/ivkos 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Created by .ignore support plugin (hsz.mobi) 2 | ### JetBrains template 3 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and Webstorm 4 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839 5 | 6 | # User-specific stuff: 7 | .idea/workspace.xml 8 | .idea/tasks.xml 9 | .idea/dictionaries 10 | .idea/vcs.xml 11 | .idea/jsLibraryMappings.xml 12 | 13 | # Sensitive or high-churn files: 14 | .idea/dataSources.ids 15 | .idea/dataSources.xml 16 | ### Composer template 17 | composer.phar 18 | /vendor/ 19 | 20 | # Commit your application's lock file http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file 21 | # You may choose to ignore a library lock file http://getcomposer.org/doc/02-libraries.md#lock-file 22 | # composer.lock 23 | .idea/dataSources.local.xml 24 | .idea/sqlDataSources.xml 25 | .idea/dynamic.xml 26 | .idea/uiDesigner.xml 27 | 28 | # Gradle: 29 | .idea/gradle.xml 30 | .idea/libraries 31 | 32 | # Mongo Explorer plugin: 33 | .idea/mongoSettings.xml 34 | 35 | ## File-based project format: 36 | *.iws 37 | 38 | ## Plugin-specific files: 39 | 40 | # IntelliJ 41 | /out/ 42 | .idea/ 43 | 44 | # mpeltonen/sbt-idea plugin 45 | .idea_modules/ 46 | 47 | # JIRA plugin 48 | atlassian-ide-plugin.xml 49 | 50 | # Crashlytics plugin (for Android Studio and IntelliJ) 51 | com_crashlytics_export_strings.xml 52 | crashlytics.properties 53 | crashlytics-build.properties 54 | fabric.properties 55 | 56 | -------------------------------------------------------------------------------- /src/Pushbullet/Contact.php: -------------------------------------------------------------------------------- 1 | $v) { 17 | $this->$k = $v ?: null; 18 | } 19 | 20 | $this->apiKey = $apiKey; 21 | 22 | if (isset($this->email)) { 23 | $this->setPushableRecipient("email", $this->email); 24 | $this->pushable = true; 25 | } else { 26 | $this->pushable = false; 27 | } 28 | } 29 | 30 | /** 31 | * Change the contact's name. 32 | * 33 | * @param string $name New name. 34 | * 35 | * @return Contact The same contact with a different name. 36 | * @throws Exceptions\ConnectionException 37 | */ 38 | public function changeName($name) 39 | { 40 | return new Contact( 41 | Connection::sendCurlRequest(Connection::URL_CONTACTS . '/' . $this->iden, 'POST', ['name' => $name], true, 42 | $this->apiKey), $this->apiKey 43 | ); 44 | } 45 | 46 | /** 47 | * Delete the contact. 48 | * 49 | * @throws Exceptions\ConnectionException 50 | */ 51 | public function delete() 52 | { 53 | Connection::sendCurlRequest(Connection::URL_CONTACTS . '/' . $this->iden, 'DELETE', null, false, 54 | $this->apiKey); 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/Pushbullet/Device.php: -------------------------------------------------------------------------------- 1 | $v) { 17 | $this->$k = $v ?: null; 18 | } 19 | 20 | $this->apiKey = $apiKey; 21 | 22 | $this->setPushableRecipient("device", $this->iden); 23 | } 24 | 25 | /** 26 | * Send an SMS message from the device. 27 | * 28 | * @param string $toNumber Phone number of the recipient. 29 | * @param string $message Text of the message. 30 | * 31 | * @return Push 32 | * @throws Exceptions\ConnectionException 33 | * @throws Exceptions\NoSmsException Thrown if the device cannot send SMS messages. 34 | */ 35 | public function sendSms($toNumber, $message) 36 | { 37 | if (empty($this->has_sms)) { 38 | throw new Exceptions\NoSmsException("Device cannot send SMS messages."); 39 | } 40 | 41 | $data = [ 42 | 'type' => 'push', 43 | 'push' => [ 44 | 'type' => 'messaging_extension_reply', 45 | 'package_name' => 'com.pushbullet.android', 46 | 'source_user_iden' => (new Pushbullet($this->apiKey))->getUserInformation()->iden, 47 | 'target_device_iden' => $this->iden, 48 | 'conversation_iden' => $toNumber, 49 | 'message' => $message 50 | ] 51 | ]; 52 | 53 | return new Push( 54 | Connection::sendCurlRequest(Connection::URL_EPHEMERALS, 'POST', $data, true, $this->apiKey), 55 | $this->apiKey 56 | ); 57 | } 58 | 59 | /** 60 | * Get the device's phonebook. 61 | * 62 | * @return PhonebookEntry[] Phonebook entries. 63 | * @throws Exceptions\ConnectionException 64 | */ 65 | public function getPhonebook() 66 | { 67 | $entries = Connection::sendCurlRequest(Connection::URL_PHONEBOOK . '_' . $this->iden, 'GET', null, false, 68 | $this->apiKey)->phonebook; 69 | 70 | $objEntries = []; 71 | foreach ($entries as $e) { 72 | $objEntries[] = new PhonebookEntry($e, $this); 73 | } 74 | 75 | return $objEntries; 76 | } 77 | 78 | /** 79 | * Delete the device. 80 | * 81 | * @throws Exceptions\ConnectionException 82 | */ 83 | public function delete() 84 | { 85 | Connection::sendCurlRequest(Connection::URL_DEVICES . '/' . $this->iden, 'DELETE', null, false, 86 | $this->apiKey); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/Pushbullet/Connection.php: -------------------------------------------------------------------------------- 1 | = 400) { 101 | if ($httpCode === 401 || $httpCode === 403) { 102 | throw new Exceptions\InvalidTokenException($json->error->message); 103 | } else if ($httpCode === 404) { 104 | throw new Exceptions\NotFoundException($json->error->message); 105 | } else { 106 | throw new Exceptions\ConnectionException( 107 | 'HTTP Error ' . $httpCode . ' (' . $json->error->type . '): ' . $json->error->message, 108 | $httpCode 109 | ); 110 | } 111 | } 112 | 113 | return $json; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/Pushbullet/Channel.php: -------------------------------------------------------------------------------- 1 | $v) { 22 | $this->$k = $v ?: null; 23 | } 24 | 25 | if (isset($properties->channel)) { 26 | $this->type = "subscription"; 27 | $this->channelTag = $properties->channel->tag; 28 | } else { 29 | $this->type = "channel"; 30 | $this->channelTag = $this->tag; 31 | } 32 | 33 | if (!empty($this->myChannel)) { 34 | $this->pushable = true; 35 | } 36 | 37 | $this->apiKey = $apiKey; 38 | 39 | $this->setPushableRecipient("channel", $this->channelTag); 40 | } 41 | 42 | /** 43 | * Subscribe to the channel. 44 | * 45 | * @return Channel Subscription. 46 | * @throws Exceptions\ConnectionException 47 | * @throws Exceptions\NotFoundException 48 | * @throws Exceptions\ChannelException 49 | */ 50 | public function subscribe() 51 | { 52 | if ($this->type == "subscription") { 53 | throw new Exceptions\ChannelException("Already subscribed to this channel."); 54 | } 55 | 56 | if (!empty($this->myChannel)) { 57 | throw new Exceptions\ChannelException("Cannot subscribe to own channel."); 58 | } 59 | 60 | try { 61 | return new Channel( 62 | Connection::sendCurlRequest(Connection::URL_SUBSCRIPTIONS, 'POST', ['channel_tag' => $this->channelTag], 63 | true, $this->apiKey), $this->apiKey 64 | ); 65 | } catch (Exceptions\ConnectionException $e) { 66 | if ($e->getCode() === 400) { 67 | throw new Exceptions\NotFoundException("Channel does not exist."); 68 | } else { 69 | throw $e; 70 | } 71 | } 72 | } 73 | 74 | /** 75 | * Unsubscribe from the channel. 76 | * 77 | * @throws Exceptions\ConnectionException 78 | * @throws Exceptions\ChannelException Thrown if the user is not subscribed to the channel. 79 | */ 80 | public function unsubscribe() 81 | { 82 | if ($this->type != "subscription") { 83 | throw new Exceptions\ChannelException("The current user is not subscribed to this channel."); 84 | } 85 | 86 | Connection::sendCurlRequest(Connection::URL_SUBSCRIPTIONS . '/' . $this->iden, 'DELETE', null, false, 87 | $this->apiKey); 88 | } 89 | 90 | /** 91 | * Get information about the channel. 92 | * 93 | * Guaranteed to always return channel information, whether or not the user is subscribed to it. It is 94 | * recommended to access the properties returned by this method, since they are consistent and always refer to 95 | * a channel, and not a subscription. 96 | * 97 | * @return Channel Channel object with information about a particular channel. 98 | * @throws Exceptions\ConnectionException 99 | * @throws Exceptions\NotFoundException 100 | */ 101 | public function getChannelInformation() 102 | { 103 | try { 104 | return new Channel( 105 | Connection::sendCurlRequest(Connection::URL_CHANNEL_INFO, 'GET', ['tag' => $this->channelTag], false, 106 | $this->apiKey), 107 | $this->apiKey 108 | ); 109 | } catch (Exceptions\ConnectionException $e) { 110 | if ($e->getCode() === 400) { 111 | throw new Exceptions\NotFoundException("Channel does not exist."); 112 | } else { 113 | throw $e; 114 | } 115 | } 116 | } 117 | 118 | /** 119 | * Create the channel if it does not exist already. 120 | * 121 | * @deprecated Channels can only be created from Pushbullet's website. 122 | * 123 | * @param string $title Channel name. 124 | * @param string $description Channel description. 125 | * 126 | * @throws Exceptions\DeprecatedException 127 | */ 128 | public function create($title, $description) 129 | { 130 | throw new Exceptions\DeprecatedException("Channels can only be created from Pushbullet's website."); 131 | } 132 | 133 | /** 134 | * Delete the channel if it is owned by the current user. 135 | * 136 | * @deprecated Channels can only be deleted from Pushbullet's website. 137 | * 138 | * @throws Exceptions\DeprecatedException 139 | */ 140 | public function delete() 141 | { 142 | throw new Exceptions\DeprecatedException("Channels can only be deleted from Pushbullet's website."); 143 | } 144 | } 145 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Pushbullet for PHP 2 | ================ 3 | [![](https://img.shields.io/packagist/v/ivkos/pushbullet.svg?style=flat-square)](https://packagist.org/packages/ivkos/pushbullet) 4 | [![](https://img.shields.io/packagist/dt/ivkos/pushbullet.svg?style=flat-square)](https://packagist.org/packages/ivkos/pushbullet) 5 | [![](https://img.shields.io/packagist/l/ivkos/pushbullet.svg?style=flat-square)](LICENSE) 6 | 7 | ## Description 8 | A PHP library for the **[Pushbullet](https://www.pushbullet.com)** API allowing you to send all supported push notification types, manage contacts, send SMS messages, create/delete channels, and manage channel subscriptions. 9 | 10 | For more information, you can refer to these links: 11 | * **Official website**: https://www.pushbullet.com 12 | * **API reference**: https://docs.pushbullet.com 13 | * **Blog**: http://blog.pushbullet.com 14 | * **Apps**: https://www.pushbullet.com/apps 15 | 16 | ## Requirements 17 | * PHP 5.4.0 or newer 18 | * Composer 19 | * cURL library for PHP 20 | * Your Pushbullet access token: https://www.pushbullet.com/account 21 | 22 | ## Install 23 | Create a `composer.json` file in your project root: 24 | 25 | ```json 26 | { 27 | "require": { 28 | "ivkos/pushbullet": "3.*" 29 | } 30 | } 31 | ``` 32 | 33 | Run `php composer.phar install` to download the library and its dependencies. 34 | 35 | ## Quick Documentation 36 | 37 | Add this line to include Composer packages: 38 | 39 | ```php 40 | getDevices(); 66 | ``` 67 | Returns an array of `Device` objects. 68 | 69 | ---------- 70 | 71 | You can target a particular device by using its `iden` or `nickname`: 72 | ```php 73 | $pb->device("Galaxy S4")->getPhonebook(); 74 | ``` 75 | Returns an array of `PhonebookEntry` objects with names and phone numbers. 76 | 77 | To target all available devices for pushing: 78 | ```php 79 | $pb->allDevices()->pushAddress("Google HQ", "1600 Amphitheatre Parkway"); 80 | ``` 81 | This will send the address to all devices, and return a `Push` object. 82 | 83 | ### Push Notifications 84 | You can use `push*` methods for `Contact`, `Channel` and `Device` objects. Every `push*` method returns a `Push` object. If an object cannot be pushed to, a `NotPushableException` will be thrown. 85 | 86 | #### Note 87 | Arguments: 88 | 89 | - Title 90 | - Body 91 | 92 | ```php 93 | $pb->device("Galaxy S4")->pushNote("Hello world!", "Lorem ipsum..."); 94 | ``` 95 | 96 | #### Link 97 | Arguments: 98 | 99 | - Title 100 | - URL 101 | - Body 102 | 103 | ```php 104 | $pb->device("Galaxy S4")->pushLink("ivkos on GitHub", "https://github.com/ivkos", "Look at my page!"); 105 | ``` 106 | 107 | #### Address 108 | Arguments: 109 | 110 | - Name - the place's name. 111 | - Address - the place's address or a map search query. 112 | 113 | ```php 114 | $pb->device("Galaxy S4")->pushAddress("Google HQ", "1600 Amphitheatre Parkway"); 115 | ``` 116 | 117 | #### List 118 | Arguments: 119 | 120 | - Title 121 | - Array of items in the list 122 | 123 | ```php 124 | $pb->device("Galaxy S4")->pushList("Shopping List", [ 125 | "Milk", 126 | "Butter", 127 | "Eggs" 128 | ]); 129 | ``` 130 | 131 | #### File 132 | Arguments: 133 | 134 | - File path 135 | - MIME type (optional) - if `null`, MIME type will be magically guessed 136 | - Title (optional) 137 | - Body (optional) 138 | - Alternative file name (optional) - push the file as if it had this file name 139 | 140 | ```php 141 | $pb->device("Galaxy S4")->pushFile( 142 | "/home/ivkos/photos/20150314_092653.jpg", 143 | "image/jpeg", 144 | "Look at this photo!", 145 | "I think it's pretty cool", 146 | "coolphoto.jpg" 147 | ); 148 | ``` 149 | 150 | ### SMS Messaging 151 | You can send SMS messages only from supported devices. If an attempt is made to send an SMS message from a device doesn't support it, a `NoSmsException` will be thrown. 152 | 153 | ```php 154 | $pb->device("Galaxy S4")->sendSms("+359123", "Hello there!"); 155 | ``` 156 | 157 | Send an SMS text to all people in a device's phonebook: 158 | ```php 159 | $people = $pb->device("Galaxy S4")->getPhonebook(); 160 | 161 | foreach ($people as $person) { 162 | $person->sendSms("Happy New Year!"); 163 | } 164 | ``` 165 | 166 | ### Channel Management 167 | Get a list of channel subscriptions: 168 | ```php 169 | $pb->getChannelSubscriptions(); 170 | ``` 171 | Returns an array of `Channel` objects with subscription information. 172 | 173 | ---------- 174 | 175 | To subscribe or unsubscribe from channels: 176 | ```php 177 | $pb->channel("greatchannel")->subscribe(); 178 | $pb->channel("mehchannel")->unsubscribe(); 179 | ``` 180 | Subscribing to a channel will return a `Channel` object with subscription information. 181 | 182 | ---------- 183 | 184 | Get a list of channels created by the current user: 185 | ```php 186 | $pb->getMyChannels(); 187 | ``` 188 | Returns an array of `Channel` objects. 189 | 190 | ### Contact Management 191 | Contacts are people you can send push notification to. They are not to be confused with entries in a device's phonebook. 192 | 193 | To list contacts on your account: 194 | ```php 195 | $pb->getContacts(); 196 | ``` 197 | Returns an array of `Contact` objects. 198 | 199 | --- 200 | 201 | To create a contact: 202 | ```php 203 | $pb->createContact("John Doe", "johndoe@example.com"); 204 | ``` 205 | Returns a `Contact` object for the newly created contact. 206 | 207 | --- 208 | 209 | You can target a particular contact by its email or name: 210 | ```php 211 | $pb->contact("johndoe@example.com")->pushNote("Hey John!", "Where are you?"); 212 | ``` 213 | 214 | To delete a contact: 215 | ```php 216 | $pb->contact("Caroline")->delete(); 217 | ``` 218 | 219 | To change a contact's name: 220 | ```php 221 | $pb->contact("William")->changeName("Bill"); 222 | ``` 223 | Returns a `Contact` object with an updated name. 224 | 225 | 226 | ---------- 227 | 228 | 229 | ***For more detailed documentation, please refer to the PHPDoc in the source files.*** 230 | -------------------------------------------------------------------------------- /src/Pushbullet/Pushable.php: -------------------------------------------------------------------------------- 1 | recipientType = "device_iden"; 27 | $this->recipient = $recipient; 28 | } else if ($recipientType === "channel") { 29 | $this->recipientType = "channel_tag"; 30 | $this->recipient = $recipient; 31 | } else if ($recipientType === "email") { 32 | if (filter_var($recipient, FILTER_VALIDATE_EMAIL) !== false) { 33 | $this->recipientType = "email"; 34 | $this->recipient = $recipient; 35 | } else { 36 | throw new Exceptions\InvalidRecipientException("Invalid email address."); 37 | } 38 | } else { 39 | throw new Exceptions\InvalidRecipientException("Unknown recipient type."); 40 | } 41 | } 42 | 43 | /** 44 | * Push a note. 45 | * 46 | * @param string $title The note's title. 47 | * @param string $body The note's body. 48 | * 49 | * @return Push Push notification. 50 | * @throws Exceptions\ConnectionException 51 | * @throws Exceptions\NotPushableException 52 | */ 53 | public function pushNote($title, $body) 54 | { 55 | self::checkPushable(); 56 | 57 | $data = []; 58 | $data[$this->recipientType] = $this->recipient; 59 | $data['type'] = 'note'; 60 | $data['title'] = $title; 61 | $data['body'] = $body; 62 | 63 | return new Push( 64 | Connection::sendCurlRequest(Connection::URL_PUSHES, "POST", $data, true, $this->apiKey), 65 | $this->apiKey 66 | ); 67 | } 68 | 69 | /** 70 | * Push a link. 71 | * 72 | * @param string $title The link's title. 73 | * @param string $url The URL to open. 74 | * @param string $body A message associated with the link. 75 | * 76 | * @return Push Push notification. 77 | * @throws Exceptions\ConnectionException 78 | * @throws Exceptions\NotPushableException 79 | */ 80 | public function pushLink($title, $url, $body) 81 | { 82 | self::checkPushable(); 83 | 84 | $data = []; 85 | $data[$this->recipientType] = $this->recipient; 86 | $data['type'] = 'link'; 87 | $data['title'] = $title; 88 | $data['url'] = $url; 89 | $data['body'] = $body; 90 | 91 | return new Push( 92 | Connection::sendCurlRequest(Connection::URL_PUSHES, "POST", $data, true, $this->apiKey), 93 | $this->apiKey 94 | ); 95 | } 96 | 97 | /** 98 | * Push an address. 99 | * 100 | * @deprecated Pushing addresses has been deprecated in Pushbullet. 101 | * 102 | * @param string $name The place's name. 103 | * @param string $address The place's address or a map search query. 104 | * 105 | * @throws Exceptions\DeprecatedException 106 | */ 107 | public function pushAddress($name, $address) 108 | { 109 | throw new Exceptions\DeprecatedException("Pushing addresses has been deprecated in Pushbullet."); 110 | } 111 | 112 | /** 113 | * Push a list. 114 | * 115 | * @deprecated Pushing lists has been deprecated in Pushbullet. 116 | * 117 | * @param string $title The list's title. 118 | * @param string[] $items The items in the list. 119 | * 120 | * @throws Exceptions\DeprecatedException 121 | */ 122 | public function pushList($title, array $items) 123 | { 124 | throw new Exceptions\DeprecatedException("Pushing lists has been deprecated in Pushbullet."); 125 | } 126 | 127 | /** 128 | * Push a file. 129 | * 130 | * @param string $filePath The path of the file to push. 131 | * @param string $mimeType The MIME type of the file. If null, we'll try to guess it. 132 | * @param string $title The title of the push notification. 133 | * @param string $body The body of the push notification. 134 | * @param string $altFileName Alternative file name to use instead of the original one. 135 | * For example, you might want to push 'someFile.tmp' as 'image.jpg'. 136 | * 137 | * @return Push Push notification. 138 | * @throws Exceptions\ConnectionException 139 | * @throws Exceptions\FilePushException 140 | * @throws Exceptions\NotFoundException Thrown if the file does not exist or is unreadable. 141 | * @throws Exceptions\NotPushableException 142 | */ 143 | public function pushFile($filePath, $mimeType = null, $title = null, $body = null, $altFileName = null) 144 | { 145 | self::checkPushable(); 146 | 147 | $fullFilePath = realpath($filePath); 148 | 149 | if (!is_readable($fullFilePath)) { 150 | throw new Exceptions\NotFoundException('File does not exist or is unreadable.'); 151 | } 152 | 153 | if (filesize($fullFilePath) > 25 * 1024 * 1024) { 154 | throw new Exceptions\FilePushException('File size exceeds 25 MB.'); 155 | } 156 | 157 | $data = []; 158 | 159 | $data['file_name'] = $altFileName === null ? basename($fullFilePath) : $altFileName; 160 | 161 | // Try to guess the MIME type if the argument is NULL 162 | $data['file_type'] = $mimeType === null ? mime_content_type($fullFilePath) : $mimeType; 163 | 164 | // Request authorization to upload the file 165 | $response = Connection::sendCurlRequest(Connection::URL_UPLOAD_REQUEST, 'GET', $data, true, $this->apiKey); 166 | $data['file_url'] = $response->file_url; 167 | 168 | if (version_compare(PHP_VERSION, '5.5.0', '>=')) { 169 | $response->data->file = new \CURLFile($fullFilePath); 170 | } else { 171 | $response->data->file = '@' . $fullFilePath; 172 | } 173 | 174 | // Upload the file 175 | Connection::sendCurlRequest($response->upload_url, 'POST', $response->data, false, null); 176 | 177 | $data[$this->recipientType] = $this->recipient; 178 | $data['type'] = 'file'; 179 | $data['title'] = $title; 180 | $data['body'] = $body; 181 | 182 | return new Push( 183 | Connection::sendCurlRequest(Connection::URL_PUSHES, 'POST', $data, true, $this->apiKey), 184 | $this->apiKey 185 | ); 186 | } 187 | 188 | /** 189 | * Check if target is pushable. 190 | * 191 | * @throws Exceptions\NotPushableException 192 | */ 193 | private function checkPushable() 194 | { 195 | if (empty($this->pushable)) { 196 | throw new Exceptions\NotPushableException("Cannot push to this target."); 197 | } 198 | } 199 | } 200 | -------------------------------------------------------------------------------- /src/Pushbullet/Pushbullet.php: -------------------------------------------------------------------------------- 1 | apiKey = $apiKey; 28 | 29 | if (!function_exists('curl_init')) { 30 | throw new Exceptions\PushbulletException('cURL library is not loaded.'); 31 | } 32 | } 33 | 34 | /** 35 | * Get push history. 36 | * 37 | * @param int $modifiedAfter Request pushes modified after this UNIX timestamp. 38 | * @param string $cursor Request the next page via its cursor from a previous response. See the API 39 | * documentation (https://docs.pushbullet.com/http/) for a detailed description. 40 | * @param int $limit Maximum number of objects on each page. 41 | * 42 | * @return Push[] Pushes. 43 | * @throws Exceptions\ConnectionException 44 | * @throws Exceptions\InvalidTokenException 45 | */ 46 | public function getPushes($modifiedAfter = 0, $cursor = null, $limit = null) 47 | { 48 | $data = self::initData($modifiedAfter, $cursor, $limit); 49 | 50 | $pushes = Connection::sendCurlRequest(Connection::URL_PUSHES, 'GET', $data, false, $this->apiKey)->pushes; 51 | 52 | $objPushes = []; 53 | 54 | foreach ($pushes as $p) { 55 | if (!empty($p->active)) { 56 | $objPushes[] = new Push($p, $this->apiKey); 57 | } 58 | } 59 | 60 | return $objPushes; 61 | } 62 | 63 | /** 64 | * Returns a Push object with the specified iden. 65 | * 66 | * @param string $iden Iden of push notification. 67 | * @return Push Push notification object. 68 | * 69 | * @throws Exceptions\ConnectionException 70 | * @throws Exceptions\NotFoundException If there's no push notification with the specified iden 71 | */ 72 | public function push($iden) 73 | { 74 | $response = Connection::sendCurlRequest(Connection::URL_PUSHES . '/' . $iden, 'GET', null, false, $this->apiKey); 75 | 76 | return new Push($response, $this->apiKey); 77 | } 78 | 79 | /** 80 | * Get a list of available devices. 81 | * 82 | * @param int $modifiedAfter Request devices modified after this UNIX timestamp. 83 | * @param string $cursor Request the next page via its cursor from a previous response. See the API 84 | * documentation (https://docs.pushbullet.com/http/) for a detailed description. 85 | * @param int $limit Maximum number of objects on each page. 86 | * 87 | * @return Device[] Devices. 88 | * @throws Exceptions\ConnectionException 89 | * @throws Exceptions\InvalidTokenException 90 | */ 91 | public function getDevices($modifiedAfter = 0, $cursor = null, $limit = null) 92 | { 93 | $data = self::initData($modifiedAfter, $cursor, $limit); 94 | 95 | $devices = Connection::sendCurlRequest(Connection::URL_DEVICES, 'GET', $data, true, $this->apiKey)->devices; 96 | 97 | $objDevices = []; 98 | 99 | foreach ($devices as $d) { 100 | if (!empty($d->active)) { 101 | $objDevices[] = new Device($d, $this->apiKey); 102 | } 103 | } 104 | 105 | $this->devices = $objDevices; 106 | 107 | return $objDevices; 108 | } 109 | 110 | /** 111 | * Target a device by its iden or nickname. 112 | * 113 | * @param string $idenOrNickname device_iden or nickname of the device. 114 | * 115 | * @return Device The device. 116 | * @throws Exceptions\ConnectionException 117 | * @throws Exceptions\InvalidTokenException 118 | * @throws Exceptions\NotFoundException 119 | */ 120 | public function device($idenOrNickname) 121 | { 122 | if ($this->devices === null) { 123 | $this->getDevices(); 124 | } 125 | 126 | foreach ($this->devices as $d) { 127 | if ($d->iden == $idenOrNickname || $d->nickname == $idenOrNickname) { 128 | return $d; 129 | } 130 | } 131 | 132 | throw new Exceptions\NotFoundException("Device not found."); 133 | } 134 | 135 | /** 136 | * Target all devices for pushing. This method returns a pseudo-device object that can only be pushed to. It 137 | * does not support SMS, has no phonebook, and cannot be deleted. 138 | * 139 | * @return Device A pseudo-device that targets all available devices for pushing. 140 | */ 141 | public function allDevices() { 142 | return new Device([ 143 | "iden" => "", 144 | "pushable" => true, 145 | "has_sms" => false 146 | ], $this->apiKey); 147 | } 148 | 149 | /** 150 | * Create a new contact. 151 | * 152 | * @param string $name Name. 153 | * @param string $email Email address. 154 | * 155 | * @return Contact The newly created contact. 156 | * @throws Exceptions\ConnectionException 157 | * @throws Exceptions\InvalidRecipientException Thrown if the email address is invalid. 158 | * @throws Exceptions\InvalidTokenException 159 | */ 160 | public function createContact($name, $email) 161 | { 162 | if (filter_var($email, FILTER_VALIDATE_EMAIL) === false) { 163 | throw new Exceptions\InvalidRecipientException('Invalid email address.'); 164 | } 165 | 166 | $data = [ 167 | 'name' => $name, 168 | 'email' => $email 169 | ]; 170 | 171 | return new Contact( 172 | Connection::sendCurlRequest(Connection::URL_CONTACTS, 'POST', $data, true, $this->apiKey), 173 | $this->apiKey 174 | ); 175 | } 176 | 177 | /** 178 | * Get a list of contacts. 179 | * 180 | * @param int $modifiedAfter Request contacts modified after this UNIX timestamp. 181 | * @param string $cursor Request the next page via its cursor from a previous response. See the API 182 | * documentation (https://docs.pushbullet.com/http/) for a detailed description. 183 | * @param int $limit Maximum number of objects on each page. 184 | * 185 | * @return Contact[] Contacts. 186 | * @throws Exceptions\ConnectionException 187 | * @throws Exceptions\InvalidTokenException 188 | */ 189 | public function getContacts($modifiedAfter = 0, $cursor = null, $limit = null) 190 | { 191 | $data = self::initData($modifiedAfter, $cursor, $limit); 192 | 193 | $contacts = Connection::sendCurlRequest(Connection::URL_CONTACTS, 'GET', $data, false, $this->apiKey)->contacts; 194 | 195 | $objContacts = []; 196 | 197 | foreach ($contacts as $c) { 198 | if (!empty($c->active)) { 199 | $objContacts[] = new Contact($c, $this->apiKey); 200 | } 201 | } 202 | 203 | $this->contacts = $objContacts; 204 | 205 | return $objContacts; 206 | } 207 | 208 | /** 209 | * Target a contact by its name or email. 210 | * 211 | * @param string $nameOrEmail Name or email of the contact. 212 | * 213 | * @return Contact The contact. 214 | * @throws Exceptions\ConnectionException 215 | * @throws Exceptions\InvalidTokenException 216 | * @throws Exceptions\NotFoundException 217 | */ 218 | public function contact($nameOrEmail) 219 | { 220 | if ($this->contacts === null) { 221 | $this->getContacts(); 222 | } 223 | 224 | foreach ($this->contacts as $c) { 225 | if ($c->name == $nameOrEmail || $c->email == $nameOrEmail) { 226 | return $c; 227 | } 228 | } 229 | 230 | throw new Exceptions\NotFoundException("Contact not found."); 231 | } 232 | 233 | /** 234 | * Get information about the current user. 235 | * 236 | * @return object Response. 237 | * @throws Exceptions\ConnectionException 238 | * @throws Exceptions\InvalidTokenException 239 | */ 240 | public function getUserInformation() 241 | { 242 | return Connection::sendCurlRequest(Connection::URL_USERS . '/me', 'GET', null, false, $this->apiKey); 243 | } 244 | 245 | /** 246 | * Update preferences for the current user. 247 | * 248 | * @param array $preferences Preferences. 249 | * 250 | * @return object Response. 251 | * @throws Exceptions\ConnectionException 252 | * @throws Exceptions\InvalidTokenException 253 | */ 254 | public function updateUserPreferences($preferences) 255 | { 256 | return Connection::sendCurlRequest(Connection::URL_USERS . '/me', 'POST', ['preferences' => $preferences], true, 257 | $this->apiKey); 258 | } 259 | 260 | /** 261 | * Target a channel to create, subscribe to, unsubscribe from, or get information. 262 | * 263 | * @param string $tag Channel tag. 264 | * 265 | * @return Channel Channel or a subscription to a channel. 266 | * If you need information about a channel, and not a subscription to one, it is 267 | * recommended to use the getChannelInformation() method and access the properties 268 | * of the object it returns. 269 | * @throws Exceptions\ConnectionException 270 | * @throws Exceptions\InvalidTokenException 271 | */ 272 | public function channel($tag) 273 | { 274 | if ($this->channels === null) { 275 | $this->getChannelSubscriptions(); 276 | } 277 | 278 | if ($this->myChannels === null) { 279 | $this->getMyChannels(); 280 | } 281 | 282 | foreach ($this->myChannels as $c) { 283 | if ($tag == $c->tag) { 284 | $c->myChannel = true; 285 | 286 | return $c; 287 | } 288 | } 289 | 290 | foreach ($this->channels as $c) { 291 | if ($tag == $c->channel->tag) { 292 | return $c; 293 | } 294 | } 295 | 296 | return new Channel(["tag" => $tag], $this->apiKey); 297 | } 298 | 299 | /** 300 | * Get a list of the channels the current user is subscribed to. 301 | * 302 | * @param int $modifiedAfter Request contacts modified after this UNIX timestamp. 303 | * @param string $cursor Request the next page via its cursor from a previous response. See the API 304 | * documentation (https://docs.pushbullet.com/http/) for a detailed description. 305 | * @param int $limit Maximum number of objects on each page. 306 | * 307 | * @return Channel[] Channels. 308 | * @throws Exceptions\ConnectionException 309 | * @throws Exceptions\InvalidTokenException 310 | * @throws Exceptions\NotFoundException 311 | */ 312 | public function getChannelSubscriptions($modifiedAfter = 0, $cursor = null, $limit = null) 313 | { 314 | $data = self::initData($modifiedAfter, $cursor, $limit); 315 | 316 | $subscriptions = Connection::sendCurlRequest(Connection::URL_SUBSCRIPTIONS, 'GET', $data, false, 317 | $this->apiKey)->subscriptions; 318 | 319 | $objChannels = []; 320 | 321 | foreach ($subscriptions as $s) { 322 | if (!empty($s->active)) { 323 | $objChannels[] = new Channel($s, $this->apiKey); 324 | } 325 | } 326 | 327 | $this->channels = $objChannels; 328 | 329 | return $objChannels; 330 | } 331 | 332 | /** 333 | * Get a list of channels created by the current user. 334 | * 335 | * @param int $modifiedAfter Request contacts modified after this UNIX timestamp. 336 | * @param string $cursor Request the next page via its cursor from a previous response. See the API 337 | * documentation (https://docs.pushbullet.com/http/) for a detailed description. 338 | * @param int $limit Maximum number of objects on each page. 339 | * 340 | * @return Channel[] Channels. 341 | * @throws Exceptions\ConnectionException 342 | * @throws Exceptions\InvalidTokenException 343 | * @throws Exceptions\NotFoundException 344 | */ 345 | public function getMyChannels($modifiedAfter = 0, $cursor = null, $limit = null) 346 | { 347 | $data = self::initData($modifiedAfter, $cursor, $limit); 348 | 349 | $myChannels = Connection::sendCurlRequest(Connection::URL_CHANNELS, 'GET', $data, false, 350 | $this->apiKey)->channels; 351 | 352 | $objChannels = []; 353 | 354 | foreach ($myChannels as $c) { 355 | if (!empty($c->active)) { 356 | $c->myChannel = true; 357 | $objChannels[] = new Channel($c, $this->apiKey); 358 | } 359 | } 360 | 361 | $this->myChannels = $objChannels; 362 | 363 | return $objChannels; 364 | } 365 | 366 | /** 367 | * Initialize data to be sent. 368 | * 369 | * @param int $modifiedAfter Request contacts modified after this UNIX timestamp. 370 | * @param string $cursor Request the next page via its cursor from a previous response. See the API 371 | * documentation (https://docs.pushbullet.com/http/) for a detailed description. 372 | * @param int $limit Maximum number of objects on each page. 373 | * 374 | * @return array Data. 375 | */ 376 | private static function initData($modifiedAfter, $cursor, $limit) 377 | { 378 | $data = []; 379 | $data['modified_after'] = $modifiedAfter; 380 | $data['cursor'] = $cursor; 381 | $data['limit'] = $limit; 382 | 383 | return $data; 384 | } 385 | } 386 | --------------------------------------------------------------------------------