├── src ├── Builder │ ├── BuilderInterface.php │ ├── NotifySendBuilder.php │ ├── BuilderAbstract.php │ ├── GrowlNotifyWindowsBuilder.php │ ├── TerminalNotifierBuilder.php │ └── GrowlNotifyBuilder.php └── Growl.php ├── composer.json ├── LICENSE.md ├── CONTRIBUTING.md ├── CHANGELOG.md ├── CONDUCT.md └── README.md /src/Builder/BuilderInterface.php: -------------------------------------------------------------------------------- 1 | =5.4.0" 17 | }, 18 | "require-dev": { 19 | "phpunit/phpunit" : "4.*", 20 | "scrutinizer/ocular": "~1.1", 21 | "squizlabs/php_codesniffer": "2.3.*" 22 | }, 23 | "autoload": { 24 | "psr-4": { 25 | "BryanCrowe\\Growl\\": "src" 26 | } 27 | }, 28 | "autoload-dev": { 29 | "psr-4": { 30 | "BryanCrowe\\Growl\\": "src", 31 | "BryanCrowe\\Growl\\Test\\": "tests" 32 | } 33 | }, 34 | "scripts": { 35 | "test": "phpunit" 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/Builder/NotifySendBuilder.php: -------------------------------------------------------------------------------- 1 | path; 26 | 27 | if (isset($options['title'])) { 28 | $command .= " {$options['title']}"; 29 | } 30 | if (isset($options['message'])) { 31 | $command .= " {$options['message']}"; 32 | } 33 | if (isset($options['sticky']) && $options['sticky'] === true) { 34 | $command .= ' -t 0'; 35 | } 36 | 37 | return $command; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) 2016 Bryan Crowe 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 13 | > all 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 21 | > THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /src/Builder/BuilderAbstract.php: -------------------------------------------------------------------------------- 1 | path = $path; 32 | return; 33 | } 34 | 35 | throw new InvalidArgumentException( 36 | 'This constructor expects a string argument.' 37 | ); 38 | } 39 | 40 | /** 41 | * Build the command string to be executed. 42 | * 43 | * @param array $options An array of options to use for building the 44 | * command. 45 | * @return string 46 | */ 47 | abstract public function build($options); 48 | } 49 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing 2 | 3 | Contributions are **welcome** and will be fully **credited**. 4 | 5 | We accept contributions via Pull Requests on [Github](https://github.com/bcrowe/growl). 6 | 7 | 8 | ## Pull Requests 9 | 10 | - **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - The easiest way to apply the conventions is to install [PHP Code Sniffer](http://pear.php.net/package/PHP_CodeSniffer). 11 | 12 | - **Add tests!** - Your patch won't be accepted if it doesn't have tests. 13 | 14 | - **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. 15 | 16 | - **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. 17 | 18 | - **Create feature branches** - Don't ask us to pull from your master branch. 19 | 20 | - **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. 21 | 22 | - **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please squash them before submitting. 23 | 24 | 25 | ## Running Tests 26 | 27 | ``` bash 28 | $ phpunit 29 | ``` 30 | 31 | 32 | **Happy coding**! 33 | -------------------------------------------------------------------------------- /src/Builder/GrowlNotifyWindowsBuilder.php: -------------------------------------------------------------------------------- 1 | path; 26 | 27 | if (isset($options['title'])) { 28 | $command .= " /t:{$options['title']}"; 29 | } 30 | if (isset($options['image'])) { 31 | $command .= " /i:{$options['image']}"; 32 | } 33 | if (isset($options['url'])) { 34 | $command .= " /cu:{$options['url']}"; 35 | } 36 | if (isset($options['sticky']) && $options['sticky'] === true) { 37 | $command .= ' /s:true'; 38 | } 39 | if (isset($options['message'])) { 40 | $command .= " {$options['message']}"; 41 | } 42 | 43 | return $command; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/Builder/TerminalNotifierBuilder.php: -------------------------------------------------------------------------------- 1 | path; 26 | 27 | if (isset($options['title'])) { 28 | $command .= " -title {$options['title']}"; 29 | } 30 | if (isset($options['subtitle'])) { 31 | $command .= " -subtitle {$options['subtitle']}"; 32 | } 33 | if (isset($options['message'])) { 34 | $command .= " -message {$options['message']}"; 35 | } 36 | if (isset($options['image'])) { 37 | $command .= " -appIcon {$options['image']}"; 38 | } 39 | if (isset($options['contentImage'])) { 40 | $command .= " -contentImage {$options['contentImage']}"; 41 | } 42 | if (isset($options['url'])) { 43 | $command .= " -open {$options['url']}"; 44 | } 45 | 46 | return $command; 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/Builder/GrowlNotifyBuilder.php: -------------------------------------------------------------------------------- 1 | path; 26 | 27 | if (isset($options['title'])) { 28 | $command .= " -t {$options['title']}"; 29 | } 30 | if (isset($options['message'])) { 31 | $command .= " -m {$options['message']}"; 32 | } 33 | if (isset($options['image'])) { 34 | $pathInfo = pathinfo($options['image']); 35 | if (isset($pathInfo['extension'])) { 36 | $command .= " --image {$options['image']}"; 37 | } else { 38 | $command .= " -a {$options['image']}"; 39 | } 40 | } 41 | if (isset($options['url'])) { 42 | $command .= " --url {$options['url']}"; 43 | } 44 | if (isset($options['sticky']) && $options['sticky'] === true) { 45 | $command .= ' -s'; 46 | } 47 | 48 | return $command; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | 3 | All notable changes to `growl` will be documented in this file. 4 | 5 | ## 2.0.3 - 2016-03-11 6 | - Update markdown files and COC. 7 | 8 | ## 2.0.2 - 2015-10-19 9 | 10 | - Added CONDUCT.md 11 | - Updates for README file. 12 | - Allow running tests through composer script. 13 | - Updated a silly var name in test. 14 | 15 | ## 2.0.1 - 2015-09-10 16 | 17 | - Add coding standards build to Travis. 18 | - Add config file for Scrutinizer. 19 | - Updated badges in README to use Scrutinizer, etc. 20 | - Fix namespacing in tests. 21 | 22 | ## 2.0.0 - 2015-03-21 23 | 24 | - Stable 2.0.0 release. 25 | 26 | ## 2.0.0-alpha1 - 2015-03-19 27 | 28 | - Rename BuilderAbstract's '$command' property to '$path'. 29 | - Add auto-selecting of builders based on the system and available builders. 30 | - Add __toString() method to Growl class. 31 | 32 | ## 1.2.0 - 2015-02-13 33 | 34 | - Drop PHP 5.3 support. 35 | - Use short array syntax. 36 | 37 | ## 1.1.0 - 2015-02-13 38 | 39 | - Added execute() method to the Growl class. 40 | 41 | ## 1.0.0 - 2015-02-02 42 | 43 | - Stable 1.0.0 release. 44 | 45 | ## 1.0.0-beta1 - 2015-01-29 46 | 47 | - 100% test coverage. 48 | - Use PSR-4 autoloading. 49 | - Remove execute() command execution method from Growl class, and introduce buildCommand() method which returns the command's string. 50 | 51 | ## 1.0.0-alpha2 - 2015-01-05 52 | 53 | - Separate OSX Growl and Windows Growl Builders 54 | - Add individual/bulk option setters 55 | - Add optional escaping 56 | - Add optional command aliasing setting 57 | 58 | ## 1.0.0-alpha1 - 2014-11-30 59 | 60 | - Rewrote everything. Take an OOP approach to building different commands. 61 | 62 | ## 0.0.5 - 2014-11-13 63 | 64 | - General fixes. 65 | 66 | ## 0.0.4 - 2014-10-25 67 | 68 | - Added TravisCI. 69 | 70 | ## 0.0.3 - 2014-10-15 71 | 72 | - Added tests. 73 | 74 | ## 0.0.2 - 2014-09-15 75 | 76 | - Added Monolog support. 77 | 78 | ## 0.0.1 - 2014-09-12 79 | 80 | - Initial proof of concept. 81 | -------------------------------------------------------------------------------- /CONDUCT.md: -------------------------------------------------------------------------------- 1 | # Contributor Code of Conduct 2 | 3 | As contributors and maintainers of this project, and in the interest of 4 | fostering an open and welcoming community, we pledge to respect all people who 5 | contribute through reporting issues, posting feature requests, updating 6 | documentation, submitting pull requests or patches, and other activities. 7 | 8 | We are committed to making participation in this project a harassment-free 9 | experience for everyone, regardless of level of experience, gender, gender 10 | identity and expression, sexual orientation, disability, personal appearance, 11 | body size, race, ethnicity, age, religion, or nationality. 12 | 13 | Examples of unacceptable behavior by participants include: 14 | 15 | * The use of sexualized language or imagery 16 | * Personal attacks 17 | * Trolling or insulting/derogatory comments 18 | * Public or private harassment 19 | * Publishing other's private information, such as physical or electronic 20 | addresses, without explicit permission 21 | * Other unethical or unprofessional conduct 22 | 23 | Project maintainers have the right and responsibility to remove, edit, or 24 | reject comments, commits, code, wiki edits, issues, and other contributions 25 | that are not aligned to this Code of Conduct, or to ban temporarily or 26 | permanently any contributor for other behaviors that they deem inappropriate, 27 | threatening, offensive, or harmful. 28 | 29 | By adopting this Code of Conduct, project maintainers commit themselves to 30 | fairly and consistently applying these principles to every aspect of managing 31 | this project. Project maintainers who do not follow or enforce the Code of 32 | Conduct may be permanently removed from the project team. 33 | 34 | This code of conduct applies both within project spaces and in public spaces 35 | when an individual is representing the project or its community. 36 | 37 | Instances of abusive, harassing, or otherwise unacceptable behavior may be 38 | reported by contacting a project maintainer at bryan@bryan-crowe.com. All 39 | complaints will be reviewed and investigated and will result in a response that 40 | is deemed necessary and appropriate to the circumstances. Maintainers are 41 | obligated to maintain confidentiality with regard to the reporter of an 42 | incident. 43 | 44 | 45 | This Code of Conduct is adapted from the [Contributor Covenant][homepage], 46 | version 1.3.0, available at 47 | [http://contributor-covenant.org/version/1/3/0/][version] 48 | 49 | [homepage]: http://contributor-covenant.org 50 | [version]: http://contributor-covenant.org/version/1/3/0/ 51 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Growl Notifications with PHP 2 | 3 | [![Latest Version on Packagist][ico-version]][link-packagist] 4 | [![Software License][ico-license]](LICENSE.md) 5 | [![Build Status][ico-travis]][link-travis] 6 | [![Coverage Status][ico-scrutinizer]][link-scrutinizer] 7 | [![Quality Score][ico-code-quality]][link-code-quality] 8 | [![Total Downloads][ico-downloads]][link-downloads] 9 | 10 | This package aims to provide an easy and fluent interface to construct and 11 | execute commands for various desktop notification programs. 12 | 13 | ## Requirements 14 | 15 | PHP 5.4+ and one of the following notification programs: 16 | 17 | ### OS X 18 | 19 | #### Growl & GrowlNotify 20 | 21 | * [Growl](http://growl.info/downloads) 22 | * [GrowlNotify](http://growl.info/downloads#generaldownloads) 23 | 24 | #### terminal-notifier 25 | 26 | ```bash 27 | $ gem install terminal-notifier 28 | $ brew install terminal-notifier 29 | ``` 30 | 31 | ### Linux 32 | 33 | #### notify-send 34 | 35 | ``` bash 36 | $ apt-get install libnotify-bin 37 | $ yum install libnotify 38 | ``` 39 | 40 | ### Windows 41 | 42 | #### Growl & GrowlNotify 43 | 44 | * [Growl](http://www.growlforwindows.com/gfw/default.aspx) 45 | * [GrowlNotify](http://www.growlforwindows.com/gfw/help/growlnotify.aspx) 46 | 47 | ## Installation 48 | 49 | ### Composer 50 | 51 | ``` bash 52 | $ composer require bcrowe/growl 53 | ``` 54 | 55 | ## Usage 56 | 57 | Create a new instance of the `Growl` class. You can optionally supply a 58 | `Builder` class and its path if you don't wish for the package to choose 59 | a notification program based on your system: 60 | 61 | ```php 62 | 74 | ``` 75 | 76 | Now, you can set key/value options for a `Builder` to use with the `setOption()` 77 | or `setOptions()` methods. After setting options, the last thing to do is build 78 | the command with `buildCommand()` or run it with `execute()`: 79 | 80 | ```php 81 | setOption('title', 'Hello World') 84 | ->setOption('message', 'How are you doing?') 85 | ->setOption('sticky', true) 86 | ->execute(); 87 | 88 | // Or... 89 | 90 | $Growl = new Growl; 91 | $Growl->setOptions([ 92 | 'title' => 'Hello World', 93 | 'message' => 'How are you doing?', 94 | 'sticky' => true 95 | ]) 96 | ->buildCommand(); 97 | 98 | exec($Growl); 99 | ?> 100 | ``` 101 | 102 | By default, this package will escape all command arguments that are supplied as 103 | options. If you want to change this, there are two options. Either completely 104 | disable escaping, or provide a safe-list of option keys that will be bypassed 105 | while escaping is enabled. 106 | 107 | ```php 108 | setOptions([ 112 | 'title' => 'Hello World', 113 | 'message' => 'How are you doing?', 114 | 'url' => 'http://www.google.com' 115 | ]) 116 | ->setEscape(false) 117 | ->execute(); 118 | 119 | // Set a safe-list of option keys. Can be an array of option keys, or a string. 120 | (new Growl) 121 | ->setOptions([ 122 | 'title' => 'Hello World', 123 | 'message' => $mySafeMessage, 124 | 'url' => $mySafeURL 125 | ]) 126 | ->setSafe(['message', 'url']) 127 | ->execute(); 128 | ?> 129 | ``` 130 | 131 | ### Builders 132 | 133 | #### GrowlNotifyBuilder & GrowlNotifyWindowsBuilder 134 | 135 | Builds commands for `growlnotify`. 136 | 137 | Available option keys: 138 | 139 | * **title** *string* The title of the growl. 140 | * **message** *string* The growl's body. 141 | * **sticky** *boolean* Whether or not make the growl stick until closed. 142 | * **image** *string* A name of an application's icon to use, e.g., "Mail" 143 | *(OS X only)*, the path to a file on the system *(OS X & Windows)*, or a URL to 144 | an image *(Windows only)*. 145 | * **url** *string* A URL to open if the growl is clicked. 146 | 147 | #### TerminalNotifierBuilder 148 | 149 | Builds commands for `terminal-notifier`. 150 | 151 | Available option keys: 152 | 153 | * **title** *string* The title of the notification. 154 | * **subtitle** *string* The notification's subtitle. 155 | * **message** *string* The notification's body. 156 | * **image** *string* A URL to an image to be used as the icon. 157 | *(OS X Mavericks+ only)* 158 | * **contentImage** *string* A URL to an image to be in the notification body. 159 | *(OS X Mavericks+ only)* 160 | * **url** *string* A URL to go to when the notification is clicked. 161 | 162 | #### NotifySendBuilder 163 | 164 | Builds commands for `notify-send`. 165 | 166 | Available option keys: 167 | 168 | * **title** *string* The title of the notification. 169 | * **message** *string* The notification's body. 170 | * **sticky** *boolean* Whether or not make the notification stick until closed. 171 | 172 | ## Changelog 173 | 174 | Please see [CHANGELOG](CHANGELOG.md) for more information what has changed 175 | recently. 176 | 177 | ## Testing 178 | 179 | ``` bash 180 | $ composer test 181 | ``` 182 | 183 | ## Contributing 184 | 185 | Please see [CONTRIBUTING](CONTRIBUTING.md) and [CONDUCT](CONDUCT.md) for details. 186 | 187 | ## Security 188 | 189 | If you discover any security related issues, please email bryan@bryan-crowe.com 190 | instead of using the issue tracker. 191 | 192 | ## Credits 193 | 194 | - [Bryan Crowe][link-author] 195 | - [All Contributors][link-contributors] 196 | 197 | ## License 198 | 199 | The MIT License (MIT). Please see [License File](LICENSE.md) for more 200 | information. 201 | 202 | [ico-version]: https://img.shields.io/packagist/v/bcrowe/growl.svg?style=flat-square 203 | [ico-license]: https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square 204 | [ico-travis]: https://img.shields.io/travis/bcrowe/growl/master.svg?style=flat-square 205 | [ico-scrutinizer]: https://img.shields.io/scrutinizer/coverage/g/bcrowe/growl.svg?style=flat-square 206 | [ico-code-quality]: https://img.shields.io/scrutinizer/g/bcrowe/growl.svg?style=flat-square 207 | [ico-downloads]: https://img.shields.io/packagist/dt/bcrowe/growl.svg?style=flat-square 208 | 209 | [link-packagist]: https://packagist.org/packages/bcrowe/growl 210 | [link-travis]: https://travis-ci.org/bcrowe/growl 211 | [link-scrutinizer]: https://scrutinizer-ci.com/g/bcrowe/growl/code-structure 212 | [link-code-quality]: https://scrutinizer-ci.com/g/bcrowe/growl 213 | [link-downloads]: https://packagist.org/packages/bcrowe/growl 214 | [link-author]: https://github.com/bcrowe 215 | [link-contributors]: ../../contributors 216 | -------------------------------------------------------------------------------- /src/Growl.php: -------------------------------------------------------------------------------- 1 | builder = $this->selectBuilder(); 69 | return; 70 | } 71 | if ($builder instanceof BuilderAbstract) { 72 | $this->builder = $builder; 73 | return; 74 | } 75 | 76 | throw new InvalidArgumentException( 77 | 'This constructor expects null or a BuilderAbstract instance.' 78 | ); 79 | } 80 | 81 | /** 82 | * Allow this object to be treated as a string in the case of using the 83 | * buildCommand() method instead of executing the command. 84 | * 85 | * @return string 86 | */ 87 | public function __toString() 88 | { 89 | return $this->command; 90 | } 91 | 92 | /** 93 | * Executes the command on your machine. 94 | * 95 | * @codeCoverageIgnore 96 | * @return void 97 | */ 98 | public function execute() 99 | { 100 | if ($this->escape !== false) { 101 | $this->options = $this->escape($this->options); 102 | } 103 | if ($this->builder !== null) { 104 | $command = $this->builder->build($this->options); 105 | exec($command); 106 | } 107 | } 108 | 109 | /** 110 | * Builds the command. 111 | * 112 | * @return string 113 | */ 114 | public function buildCommand() 115 | { 116 | if ($this->escape !== false) { 117 | $this->options = $this->escape($this->options); 118 | } 119 | if ($this->builder !== null) { 120 | $this->command = $this->builder->build($this->options); 121 | } 122 | 123 | return $this; 124 | } 125 | 126 | /** 127 | * Set options for Builders with a key/value. 128 | * 129 | * @param string $key The key. 130 | * @param array $value The value of the key. 131 | * @return $this 132 | */ 133 | public function setOption($key, $value) 134 | { 135 | $this->options[$key] = $value; 136 | 137 | return $this; 138 | } 139 | 140 | /** 141 | * Set an entire set of options for a Builder. This is available so a user 142 | * bulk-set options rather than chaining set() calls. 143 | * 144 | * @param array $options The entire set of options. 145 | * @return $this 146 | */ 147 | public function setOptions(array $options) 148 | { 149 | foreach ($options as $key => $value) { 150 | $this->options[$key] = $value; 151 | } 152 | 153 | return $this; 154 | } 155 | 156 | /** 157 | * Set the escape properties value. Set it to false to disable command 158 | * argument escaping. 159 | * 160 | * @param boolean $value Pass false to disable escaping. 161 | * @return $this 162 | */ 163 | public function setEscape($value) 164 | { 165 | $this->escape = $value; 166 | 167 | return $this; 168 | } 169 | 170 | /** 171 | * Sets option names that are considered safe, in order to bypass escaping. 172 | * 173 | * @param mixed A string or array of option names assumed to be safe from 174 | * escaping. 175 | * @throws \InvalidArgumentException If the method argument isn't a string or 176 | * array. 177 | * @return $this 178 | */ 179 | public function setSafe($options) 180 | { 181 | if (is_string($options)) { 182 | $this->safe[] = $options; 183 | return $this; 184 | } 185 | 186 | if (is_array($options)) { 187 | foreach ($options as $key => $value) { 188 | $this->safe[] = $value; 189 | } 190 | return $this; 191 | } 192 | 193 | throw new InvalidArgumentException( 194 | 'This method expects a string or an array argument.' 195 | ); 196 | } 197 | 198 | /** 199 | * Escapes the set of option values. 200 | * 201 | * @param array A set of key/value options. 202 | * @return array The sanitized set of key/value options. 203 | */ 204 | protected function escape(array $options) 205 | { 206 | $results = []; 207 | foreach ($options as $key => $value) { 208 | if (!in_array($key, $this->safe)) { 209 | $results[$key] = escapeshellarg($value); 210 | } else { 211 | $results[$key] = $value; 212 | } 213 | } 214 | 215 | return $results; 216 | } 217 | 218 | /** 219 | * Chooses a Builder to use depending on the operating system and which 220 | * program is installed. 221 | * 222 | * @codeCoverageIgnore 223 | * @return \BryanCrowe\Growl\Builder\BuilderAbstract A suitable Builder for 224 | * a notification program that was found on the system. 225 | */ 226 | protected function selectBuilder() 227 | { 228 | if (PHP_OS === 'Darwin') { 229 | if (exec('which growlnotify')) { 230 | return new GrowlNotifyBuilder; 231 | } 232 | if (exec('which terminal-notifier')) { 233 | return new TerminalNotifierBuilder; 234 | } 235 | } 236 | if (PHP_OS === 'Linux') { 237 | if (exec('which notify-send')) { 238 | return new NotifySendBuilder; 239 | } 240 | } 241 | if (PHP_OS === 'WINNT') { 242 | if (exec('where growlnotify')) { 243 | return new GrowlNotifyWindowsBuilder; 244 | } 245 | } 246 | } 247 | } 248 | --------------------------------------------------------------------------------